Combining Gui.Add() and onEvent() functions on a single line is appealing as a programming technique (see below). However, this can lead to unexpected issues.
Gui.Add() returns the GuiControl object (GuiCtrl) for the control that was added. This is a powerful reference that you will want to have if you are going to interact with the control.
OnEvent() when registered to a GuiCtrl without a Callback returns a null string
When you combine the Gui.Add() and the onEvent() functions in a single line of code (see below) the final value returned is the NullString returned by onEvent() not the GuiCtrl returned by GuiAdd(). When combined the GuiCtrl object returned by Gui.Add() is used to register the onEvent() with the newly added control and the return value is a string returned by onEvent().
THIS LINE IS VALID CODE:
RA := main.addRadio("vTesting", "Test1").onEvent("Click", React) ;here RA = NullString (no onEvent callback)
...
ControlClick RA ;Generates an error because RA is not a valid GuiCtrl object
IT IS NOT THE SAME AS THE FOLLOWING (WHICH IS ALSO VALID CODE):
RA := main.addRadio("vTesting", "Test1") ;here RA = the GuiCtrl object for the added radio button
RA.onEvent("Click", React)
...
ControlClick RA ;Clicks the RA radio button
--- THIS PRECAUTION HOLDS FOR COMBINING FUNCTIONS ANYWHERE IN AHK ---
Moderator's Note: Moved from Scripts and Functions to Tips and Tricks
A caution about combining Gui.Add and onEvent functions
- FanaticGuru
- Posts: 1907
- Joined: 30 Sep 2013, 22:25
Re: A caution about combining Gui.Add and onEvent functions
.OnEvent on the end looked cool when I first saw it but I pretty much never do it now unless the script is really simple. You can do this if you like to keep on one line:
MyButton := MyGui.Add('Button',,'Ok'), MyButton.OnEvent('Click', Handler_Click)
Here is how I like doing things.
Code: Select all
guiInfoDialog := Gui('+AlwaysOnTop -MinimizeBox')
guiInfoDialog.TextW := guiInfoDialog.Add('Text', 'y20', 'Width')
guiInfoDialog.EditW := guiInfoDialog.Add('Edit', 'r1 w40 x50 yp')
guiInfoDialog.TextH := guiInfoDialog.Add('Text', 'xp+60 yp', 'Height')
guiInfoDialog.EditH := guiInfoDialog.Add('Edit', 'r1 w40 xp+50 yp')
guiInfoDialog.CheckRatio := guiInfoDialog.Add('CheckBox', 'xp+60 yp-10', 'Lock Ratio')
guiInfoDialog.CheckRatio.OnEvent('Click', guiInfoDialog_Click)
guiInfoDialog.CheckWH := guiInfoDialog.Add('CheckBox', 'xp yp+20', 'Display W x H')
guiInfoDialog.CheckWH.OnEvent('Click', guiInfoDialog_Click)
guiInfoDialog.ButtonApply := guiInfoDialog.Add('Button', 'Default xm yp+40 w80', 'Apply')
guiInfoDialog.ButtonApply.OnEvent('Click', guiInfoDialog_Click)
guiInfoDialog.ButtonOK := guiInfoDialog.Add('Button', 'yp xp+100 w80', 'Ok')
guiInfoDialog.ButtonOK.OnEvent('Click', guiInfoDialog_Click)
guiInfoDialog.ButtonCancel := guiInfoDialog.Add('Button', 'yp xp+100 w80', 'Cancel')
guiInfoDialog.ButtonCancel.OnEvent('Click', guiInfoDialog_Click)
guiInfoDialog.Show
F12:: guiInfoDialog.Show ; Show dialog after closing with Ok or Cancel
guiInfoDialog_Click(GuiCtrlObj, Info)
{
Switch GuiCtrlObj.Text
{
Case 'Lock Ratio', 'Display W x H' :
{
ToolTip GuiCtrlObj.Text ' = ' GuiCtrlObj.Value
}
Case 'Apply':
{
Width := guiInfoDialog.EditW.Value, Height := guiInfoDialog.EditH.Value
ToolTip 'W x H ' Width 'x' Height
}
Case 'Ok':
{
Width := guiInfoDialog.EditW.Value, Height := guiInfoDialog.EditH.Value
ToolTip 'W x H ' Width 'x' Height '`nOk'
guiInfoDialog.Hide
}
Case 'Cancel':
{
ToolTip 'Cancel'
guiInfoDialog.Hide
}
}
}
I like to store all my controls in the same object as the Gui object. It is then easy to enumerate through all the controls for something like a Size event for example.
I also like to limit my OnEvent functions and have functions handle multiple events and then just sort out which control within the handler function.
FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
Re: A caution about combining Gui.Add and onEvent functions
Can’t you just loop over the GUI object to loop through the controls?
- FanaticGuru
- Posts: 1907
- Joined: 30 Sep 2013, 22:25
Re: A caution about combining Gui.Add and onEvent functions
That is true. That was a poor example.
The main take away is that a Gui object is still very much like a standard object in that other objects can be nested inside it. Whether they are other gui, gui controls, maps, arrays, properties, etc. Even functions, classes, and methods, although I have not tried or had a need for that yet.
I often keep position information in the Gui object for its controls and then only enumerate through certain controls when resizing with rules for how different groups are moved.
I was trying to keep it simpler, but he is a more robust example of storing additional information in the Gui object.
Code: Select all
guiInfoDialog := Gui('+AlwaysOnTop -MinimizeBox')
guiInfoDialog.Text := {}, guiInfoDialog.Edit := {}, guiInfoDialog.Check := {}, guiInfoDialog.Button := {}
guiInfoDialog.Text.W := guiInfoDialog.Add('Text', 'y20', 'Width')
guiInfoDialog.Edit.W := guiInfoDialog.Add('Edit', 'r1 w40 x50 yp')
guiInfoDialog.Text.H := guiInfoDialog.Add('Text', 'xp+60 yp', 'Height')
guiInfoDialog.Edit.H := guiInfoDialog.Add('Edit', 'r1 w40 xp+50 yp')
guiInfoDialog.Check.Ratio := guiInfoDialog.Add('CheckBox', 'xp+60 yp-10', 'Lock Ratio')
guiInfoDialog.Check.Ratio.OnEvent('Click', guiInfoDialog_Click)
guiInfoDialog.Check.WH := guiInfoDialog.Add('CheckBox', 'xp yp+20', 'Display W x H')
guiInfoDialog.Check.WH.OnEvent('Click', guiInfoDialog_Click)
guiInfoDialog.Button.Apply := guiInfoDialog.Add('Button', 'Default xm yp+40 w80', 'Apply')
guiInfoDialog.Button.Apply.OnEvent('Click', guiInfoDialog_Click)
guiInfoDialog.Button.OK := guiInfoDialog.Add('Button', 'yp xp+100 w80', 'Ok')
guiInfoDialog.Button.OK.OnEvent('Click', guiInfoDialog_Click)
guiInfoDialog.Button.Cancel := guiInfoDialog.Add('Button', 'yp xp+100 w80', 'Cancel')
guiInfoDialog.Button.Cancel.OnEvent('Click', guiInfoDialog_Click)
guiInfoDialog.Button.Apply.Help := 'Set Input Without Closing Gui'
guiInfoDialog.Button.Ok.Help := 'Set Input and Close Gui'
guiInfoDialog.Button.Cancel.Help := 'Close Gui Without Setting Input'
guiInfoDialog.Show
F11:: ; Clear all Check Marks (something similar could be used for saving and loading settings to an ini file)
{
For each, GuiCtrlObj in guiInfoDialog.Check.OwnProps()
GuiCtrlObj.Value := 0
}
F12:: guiInfoDialog.Show ; Show dialog after closing with Ok or Cancel
guiInfoDialog_Click(GuiCtrlObj, Info)
{
Switch GuiCtrlObj.Text
{
Case 'Lock Ratio', 'Display W x H':
{
ToolTip GuiCtrlObj.Text ' = ' GuiCtrlObj.Value
}
Case 'Apply':
{
Width := guiInfoDialog.Edit.W.Value, Height := guiInfoDialog.Edit.H.Value
ToolTip 'W x H ' Width 'x' Height
}
Case 'Ok':
{
Width := guiInfoDialog.Edit.W.Value, Height := guiInfoDialog.Edit.H.Value
ToolTip 'W x H ' Width 'x' Height '`nOk'
guiInfoDialog.Hide
}
Case 'Cancel':
{
ToolTip 'Cancel'
guiInfoDialog.Hide
}
}
}
; Setup message events and handling for hovering
OnMessage(WM_MOUSEMOVE := 0x0200, OnMouseEvent)
OnMessage(WM_MOUSELEAVE := 0x02A3, OnMouseEvent)
OnMouseEvent(wp, lp, msg, hwnd)
{
Static TME_LEAVE := 0x2, onHover := false
If msg = WM_MOUSEMOVE && !onHover
{
TRACKMOUSEEVENT := Buffer(8 + A_PtrSize * 2)
NumPut('UInt', TRACKMOUSEEVENT.Size,
'UInt', TME_LEAVE,
'Ptr', hwnd,
'Ptr', 10, TRACKMOUSEEVENT)
DllCall('TrackMouseEvent', 'Ptr', TRACKMOUSEEVENT)
HelpToolTip(onHover := true, hwnd)
}
If msg = WM_MOUSELEAVE
{
HelpToolTip(onHover := false, hwnd)
}
}
HelpToolTip(Hover, Hwnd)
{
If Hover
{
Try
{
CoordMode('ToolTip', 'Window')
GuiCtrlObj := GuiCtrlFromHwnd(Hwnd)
GuiCtrlObj.GetPos(&X, &Y, &Width, &Height)
ToolTip(GuiCtrlObj.Help, X, Y + Height)
}
}
Else
ToolTip
}
But I understand it could be a little verbose for some peoples taste.
FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
Re: A caution about combining Gui.Add and onEvent functions
Single line and single expression:
Code: Select all
(RA := main.addRadio("vTesting", "Test1")).onEvent("Click", React) ;here RA = the GuiCtrl object for the added radio button)
- FanaticGuru
- Posts: 1907
- Joined: 30 Sep 2013, 22:25
Re: A caution about combining Gui.Add and onEvent functions
just me wrote: ↑22 Apr 2023, 04:55Single line and single expression:Code: Select all
(RA := main.addRadio("vTesting", "Test1")).onEvent("Click", React) ;here RA = the GuiCtrl object for the added radio button)
That seems pretty good. I am surprised I have not seen it or thought of it myself.
Makes for kind of long lines but I like having a control and its event on the same line.
FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
Who is online
Users browsing this forum: No registered users and 8 guests