EDIT: Found a way to shorten the GuiControl wrapper even further. Still can't get much shorter. Without the defined
properties[] (and trying to use __Get() and __Set() ) I end up getting circular references.
EDIT2: Managed to store some GuiControl properties (that don't change) in
this.property. The rest need to be read from GuiControl object.
Just wanted to finish this train of thought. The only way I've found to extend GuiControls is to completely wrap them.
Code: Select all
Global g
g := gui2.New(,"Test Gui")
g.OnEvent("close","gui_close")
g.Add("Edit","vMyEdit1 w200 r4 Section").OnCommand(0x300,"some_event") ; same as "Change" for OnEvent ; EN_CHANGE
g.Add("Edit","vMyEdit2 ReadOnly w200 r2")
g.Add("Edit","vMyEdit3 ReadOnly w200 r2")
g.Add("Edit","vMyEdit4 ReadOnly w200 h100")
g.Add("Button","vBtn1 w100","Test1").OnEvent("click","ctl_events")
g.Add("Button","vBtn2 x+0 w100","Test2").OnEvent("click","ctl_events")
g.Add("Button","vBtn3 x+10 w100","Adj Col").OnEvent("click","ctl_events")
ctl := g.Add("ListView","vLV x220 ym w200",["Stuff"])
ctl.Add(,"Row1"), ctl.Add(,"Row2"), ctl.Add(,"Row3")
g.Show()
return
class gui2 extends gui2._gui_important_stuff {
test2 := "property added"
; put user props / methods for GUI here
test() { ; pointless method, just to illustrate adding custom methods.
return "method added" ; Use "super" or "this" to access the original GUI object and it's methods/properties.
}
some_event(ctl) { ; Custom user function for WM_COMMAND notifications, used with Gui "event sink" (EventObj)
this["MyEdit4"].Value := "Title: " ctl.Name "`r`n`r`n" ctl.value
}
gui_close(*) { ; Custom user function for close event; used with Gui "event sink"
ExitApp
}
msg(wParam, lParam, msg, hwnd) { ; Custom user function for OnMessage, used with Gui "event sink"
this["MyEdit2"].Value := "Mouse Move / wParam: " wParam "`r`nlParam: " lParam " / hwnd: " hwnd
return
}
Call(wParam, lParam, msg, hwnd) { ; Custom user function when func obj is needed... OnMessage() in this case.
state := (wParam) ? "Down" : "Up"
this["MyEdit3"].Value := "LB " state " / wParam: " wParam "`r`nlParam: " lParam " / hwnd: " hwnd
}
ctl_events(ctl, p*) { ; Custom user function for GUI control events when using "event sink"
ctl := GuiCtl.New(ctl)
If ctl.Name = "Btn1"
msgbox "test method:`t" g.test() "`r`ntest property:`t" g.test2 "`r`ntest property:`t" g.test3
Else If ctl.Name = "Btn2" {
If (g["MyEdit1"].Enabled) {
g["MyEdit1"].Enabled := false
pos := g["MyEdit4"].GetPos()
g["MyEdit4"].Move(pos.x+20,,pos.w-20)
g["MyEdit2"].SetFont("s10","Times New Roman")
g["MyEdit4"].Value := "setting Value prop for: " g["MyEdit4"].Name
g.Title := "Testing..."
} Else {
g["MyEdit1"].Enabled := true
pos := g["MyEdit4"].GetPos()
g["MyEdit4"].Move(pos.x-20,,pos.w+20)
g["MyEdit2"].SetFont("s8","Verdana")
g["MyEdit4"].Value := "setting Value prop for: " g["MyEdit4"].Name
g.Title := "Test GUI"
}
} Else If ctl.Name = "Btn3" {
ctl.gui["LV"].ModifyCol(1,100)
If ctl.gui["LV"].GetCount()
ctl.gui["LV"].Delete()
Else {
ctl.gui["LV"].Add(,"Row1")
ctl.gui["LV"].Add(,"Row2")
ctl.gui["LV"].Add(,"Row3")
ctl.gui["LV"].ModifyCol(1,190)
}
}
}
class _gui_important_stuff extends gui { ; put the important stuff out of the way
test3 := "another prop"
__New(opt:="", title:="", EventObj:="") {
super.__New(opt, title, this) ; Specify the event sink for the GUI obj as this subclass.
; Required when func obj is needed and using a user class.
OnMessage(0x200,ObjBindMethod(this,"msg")) ; WM_MOUSEMOVE ; binding these outside the class doesn't work too well
; ... best to do this in the class somewhere
OnMessage(0x201,this) ; WM_LBUTTONDOWN ; these can be bound outside the class, because they are using .Call() method.
OnMessage(0x202,this) ; WM_LBUTTONUP
}
__Item[key] {
get => GuiCtl.New(super[key]) ; should be ReadOnly
}
Add(type, options:="", value:="") {
return GuiCtl.New(super.Add(type, options, value))
}
}
}
class GuiCtl extends GuiCtl.GuiControl {
test := "test property"
; put other properties / methods here!
class GuiControl {
__New(ctl) {
this.GuiCtlObj := ctl ; store the original control in this.GuiCtlObj
this.Type := ctl.type, this.hwnd := ctl.hwnd, this.ClassNN := ctl.ClassNN
}
Enabled[] {
get => this.GuiCtlObj.Enabled
set => this.GuiCtlObj.Enabled := value
}
Focused[] { ; This value isn't static, need to pull it
get => this.GuiCtlObj.Focused ; from the original GuiControl object.
}
Gui[] { ; Don't want to make another copy of the GUI.
get => this.GuiCtlObj.Gui ; So keeping this property.
}
Name[] {
get => this.GuiCtlObj.Name
set => this.GuiCtlObj.Name := Value
}
Text[] {
get => this.GuiCtlObj.Text
set => this.GuiCtlObj.Text := Value
}
Value[] {
get => this.GuiCtlObj.Value
set => this.GuiCtlObj.Value := value
}
__Call(key,p) {
If key = "__Init" { ; This is only for preventing an error when __Init fires.
return ; Pre-defined custom properties can still be place up top.
} Else If key = "GetPos" { ; ByRef treatment doesn't wrap well.
this.GuiCtlObj.GetPos(x, y, w, h) ; Switching back to returning an obj.
return {x:x, y:y, w:w, h:h}
} Else If key {
return this.GuiCtlObj.%key%(p*)
}
}
}
}
I think this wrapper looks pretty good considering. I tried using __Get() / __Set() but kept getting circular reference issues. This is the closest / shortest version I've come up with.
I had to handle
.GetPos() differently. The ByRef nature of the vars fed in didn't play well with this kind of wrapper. Other than that __Call() is working nicely along with
p*.
@kczx3 any idea how to shorten the GuiCtl wrapper at the bottom? The defined props seems to be the only way to read/write to the original GuiControl properties and avoid circular references (trying to use __Get and __Set).