FaridAgl Posted March 13, 2014 Share Posted March 13, 2014 (edited) Here is what I came up with, it supports MouseClick, MouseEnter, MouseLeave, MouseDown and MouseUp events. I tried to implement this in a clean way, in both coding and its logic so I followed how C#.net handles this events for a control and tried to simulate them (Guess Microsoft knows better than me!). It has an external function which you can use and a single internal function which you shouldn't call. Also there is only 1 global variable, an array which holds everything about the registred controls and their events. It could be used with GUIOnEventMode 1 and 0, and no matter if you switch GUIOnEventMode's value during the runtime. Let me know how is it going for you. Comments for improvements and suggestions are greatly welcomed. expandcollapse popup#include-once #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 Global $GUICtrlSetOnEventEx_ahEvents[1][1] Func GUICtrlSetOnEventEx($iCtrlId, $MouseClick = Null, $MouseEnter = Null, $MouseLeave = Null, $MouseDown = Null, $MouseUp = Null) ; ;Validate the control identifier ; Local $hCtrl = GUICtrlGetHandle($iCtrlId) If ($hCtrl = 0) Then Return False EndIf ; ;Validate the event functions, they must be a function, or Null ; If ((Not IsFunc($MouseClick)) And ($MouseClick <> Null)) Then Return False ElseIf ((Not IsFunc($MouseEnter)) And ($MouseEnter <> Null)) Then Return False ElseIf ((Not IsFunc($MouseLeave)) And ($MouseLeave <> Null)) Then Return False ElseIf ((Not IsFunc($MouseDown)) And ($MouseDown <> Null)) Then Return False ElseIf ((Not IsFunc($MouseUp)) And ($MouseUp <> Null)) Then Return False EndIf ; ;Delete $hCtrl and its events ; If (@NumParams = 1) Then ; ;There is no event to delete ; If ($GUICtrlSetOnEventEx_ahEvents[0][0] = 0) Then Return False EndIf Local $ahEvents[1][1] For $i = 1 To $GUICtrlSetOnEventEx_ahEvents[0][0] ; ;Skip $hCtrl as we don't want its events be listened any more ; If ($GUICtrlSetOnEventEx_ahEvents[$i][0] = $hCtrl) Then ContinueLoop EndIf $ahEvents[0][0] += 1 ReDim $ahEvents[$ahEvents[0][0] + 1][6] ; ;Control identifier ; $ahEvents[$ahEvents[0][0]][0] = $GUICtrlSetOnEventEx_ahEvents[$i][0] ; ;MouseClick event ; $ahEvents[$ahEvents[0][0]][1] = $GUICtrlSetOnEventEx_ahEvents[$i][1] ; ;MouseEnter event ; $ahEvents[$ahEvents[0][0]][2] = $GUICtrlSetOnEventEx_ahEvents[$i][2] ; ;MouseDown event ; $ahEvents[$ahEvents[0][0]][3] = $GUICtrlSetOnEventEx_ahEvents[$i][3] ; ;MouseUp event ; $ahEvents[$ahEvents[0][0]][4] = $GUICtrlSetOnEventEx_ahEvents[$i][4] ; ;MouseLeave event ; $ahEvents[$ahEvents[0][0]][5] = $GUICtrlSetOnEventEx_ahEvents[$i][5] Next ; ;If no matches found for $hCtrl ; If ($GUICtrlSetOnEventEx_ahEvents[0][0] = $ahEvents[0][0]) Then Return False EndIf ; ;Uninitialize the event listener if $hCtrl was the last one ; If ($ahEvents[0][0] = 0) Then AdlibUnRegister(GUICtrlSetOnEventEx_Proc) $GUICtrlSetOnEventEx_ahEvents = 0 Dim $GUICtrlSetOnEventEx_ahEvents[1][1] Else $GUICtrlSetOnEventEx_ahEvents = $ahEvents EndIf Return True EndIf ; ;Initialize the event listener if it's not already initialized ; If ($GUICtrlSetOnEventEx_ahEvents[0][0] = 0) Then If (AdlibRegister(GUICtrlSetOnEventEx_Proc, 10) = 0) Then Return False EndIf EndIf ; ;Update $hCtrl's events if it already exists in the event listener ; For $i = 1 To $GUICtrlSetOnEventEx_ahEvents[0][0] If ($GUICtrlSetOnEventEx_ahEvents[$i][0] = $hCtrl) Then $GUICtrlSetOnEventEx_ahEvents[$i][1] = $MouseClick $GUICtrlSetOnEventEx_ahEvents[$i][2] = $MouseEnter $GUICtrlSetOnEventEx_ahEvents[$i][3] = $MouseLeave $GUICtrlSetOnEventEx_ahEvents[$i][4] = $MouseDown $GUICtrlSetOnEventEx_ahEvents[$i][5] = $MouseUp Return True EndIf Next ; ;Add $hCtrl and its events to the event listener ; $GUICtrlSetOnEventEx_ahEvents[0][0] += 1 ReDim $GUICtrlSetOnEventEx_ahEvents[$GUICtrlSetOnEventEx_ahEvents[0][0] + 1][6] $GUICtrlSetOnEventEx_ahEvents[$GUICtrlSetOnEventEx_ahEvents[0][0]][0] = $hCtrl $GUICtrlSetOnEventEx_ahEvents[$GUICtrlSetOnEventEx_ahEvents[0][0]][1] = $MouseClick $GUICtrlSetOnEventEx_ahEvents[$GUICtrlSetOnEventEx_ahEvents[0][0]][2] = $MouseEnter $GUICtrlSetOnEventEx_ahEvents[$GUICtrlSetOnEventEx_ahEvents[0][0]][3] = $MouseLeave $GUICtrlSetOnEventEx_ahEvents[$GUICtrlSetOnEventEx_ahEvents[0][0]][4] = $MouseDown $GUICtrlSetOnEventEx_ahEvents[$GUICtrlSetOnEventEx_ahEvents[0][0]][5] = $MouseUp Return True EndFunc Func GUICtrlSetOnEventEx_Proc() ; ;These variables "must" be defined as static as we need their values to be available in the next calls ; Local Static $WasPrimaryButtonDown = False Local Static $LastHoveredCtrlId = 0 Local Static $LastHoveredCtrl = 0x0 Local Static $LastPressedCtrl = 0x0 Local Static $LastMouseUpFunction = Null Local Static $LastMouseLeaveFunction = Null ; ;Nonzero if the meanings of the left and right mouse buttons are swapped ; Local $AreMouseButtonsSwapped = DllCall("user32.dll", "int", "GetSystemMetrics", _ "int", 23)[0] ;SM_SWAPBUTTON ; ;Define the primary mouse button's value ; Local $PrimaryMouseButton = (($AreMouseButtonsSwapped = 0) ? (0x01) : (0x02)) ;VK_LBUTTON : VK_RBUTTON ; ;"<> 0" is not really necessary, but let it remain there, trust me ; Local $IsPrimaryButtonDown = (DllCall("user32.dll", "short", "GetAsyncKeyState", _ "int", $PrimaryMouseButton)[0] <> 0) ; ;Retrieves the position of the mouse cursor, in screen coordinates ; Local $tPOINT = DllStructCreate("long x;long y") DllCall("user32.dll", "BOOL", "GetCursorPos", _ "ptr", DllStructGetPtr($tPOINT)) ; ;Retrieves a handle to the window that contains the specified point ; Local $tCAST = DllStructCreate("INT64", DllStructGetPtr($tPOINT)) Local $hCtrl = DllCall("user32.dll", "HWND", "WindowFromPoint", _ "INT64", DllStructGetData($tCAST, 1))[0] ; ;Convert the control handle to control identifier ; Local $iCtrlId = DllCall("user32.dll", "int", "GetDlgCtrlID", _ "HWND", $hCtrl)[0] ; ;Wait while the primary mouse button is pressed and the cursor is not on the pressed control ; If (($hCtrl <> $LastPressedCtrl) And ($IsPrimaryButtonDown) And ($WasPrimaryButtonDown)) Then Return EndIf ; ;Return if none of the $hCtrl and $IsPrimaryButtonDown are changed ; If (($hCtrl = $LastHoveredCtrl) And ($IsPrimaryButtonDown = $WasPrimaryButtonDown)) Then Return EndIf ; ;Primary mouse button is pressed on a new control ; If (($IsPrimaryButtonDown <> $WasPrimaryButtonDown) And ($IsPrimaryButtonDown)) Then $LastPressedCtrl = $hCtrl EndIf ; ;If the current hovered control is not the previous hovered control ; If ($hCtrl <> $LastHoveredCtrl) Then ; ;Trigger previous pressed control's MouseUp event if it has one and it's not hovered anymore ; If (($LastMouseUpFunction <> Null) And (Not $IsPrimaryButtonDown) And ($WasPrimaryButtonDown) And ($LastHoveredCtrl <> 0)) Then $LastMouseUpFunction($LastHoveredCtrlId) $LastMouseUpFunction = Null EndIf ; ;Trigger previous hovered control's MouseLeave event if it has one ; If ($LastMouseLeaveFunction <> Null) Then $LastMouseLeaveFunction($LastHoveredCtrlId) $LastMouseLeaveFunction = Null EndIf EndIf ; ;Is there any event registerd for $hCtrl? Let's see! ; For $i = 1 To $GUICtrlSetOnEventEx_ahEvents[0][0] If ($GUICtrlSetOnEventEx_ahEvents[$i][0] = $hCtrl) Then ; ;If the primary mouse button is and was pressed while the cursor was on the current hovered control ; If (($IsPrimaryButtonDown) And ($hCtrl = $LastPressedCtrl)) Then ; ;Trigger MouseDown event if it has one ; If ($GUICtrlSetOnEventEx_ahEvents[$i][4] <> Null) Then $GUICtrlSetOnEventEx_ahEvents[$i][4] ($iCtrlId) Else ; ;If a new control is hovered and/or the primary mouse button state has changed ; If (($hCtrl <> $LastHoveredCtrl) Or ($IsPrimaryButtonDown <> $WasPrimaryButtonDown)) Then ; ;Current hovered control is the previous pressed control and the primary mouse button is not pressed now, but it was ; If (($hCtrl = $LastPressedCtrl) And (Not $IsPrimaryButtonDown) And ($WasPrimaryButtonDown)) Then ; ;Trigger MouseClick event if it has one ; If ($GUICtrlSetOnEventEx_ahEvents[$i][1] <> Null) Then $GUICtrlSetOnEventEx_ahEvents[$i][1] ($iCtrlId) ; ;Trigger MouseUp event if it has one ; If ($GUICtrlSetOnEventEx_ahEvents[$i][5] <> Null) Then $GUICtrlSetOnEventEx_ahEvents[$i][5] ($iCtrlId) ElseIf ($hCtrl <> $LastHoveredCtrl) Then ; ;Trigger MouseEnter event if it has one ; If ($GUICtrlSetOnEventEx_ahEvents[$i][2] <> Null) Then $GUICtrlSetOnEventEx_ahEvents[$i][2] ($iCtrlId) EndIf EndIf EndIf $LastMouseUpFunction = $GUICtrlSetOnEventEx_ahEvents[$i][5] $LastMouseLeaveFunction = $GUICtrlSetOnEventEx_ahEvents[$i][3] ExitLoop EndIf Next $WasPrimaryButtonDown = $IsPrimaryButtonDown $LastHoveredCtrlId = $iCtrlId $LastHoveredCtrl = $hCtrl EndFunc Example: expandcollapse popup#include <StaticConstants.au3> #include <GUIConstantsEx.au3> #include "GUICtrlSetOnEventEx.au3" Global $hWnd = GUICreate("GUICtrlSetOnEventEx Example", 600, 400) GUICtrlCreateButton("Button!", 25, 25, 100, 25) GUICtrlSetOnEventEx(-1, btnMouseClick, btnMouseEnter, btnMouseLeave, btnMouseDown, btnMouseUp) GUICtrlCreateLabel("LABEL", 25, 75, 100, 20, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetColor(-1, 0x1E1E1E) GUICtrlSetOnEventEx(-1, Null, lblMouseEnter, lblMouseLeave, lblMouseDown, lblMouseUp) Global $chkA = GUICtrlCreateCheckbox("Checkbox A", 25, 120, -1, 15) GUICtrlSetOnEventEx(-1, Null, chkMouseEnter) Global $chkB = GUICtrlCreateCheckbox("Checkbox B", 25, 140, -1, 15) GUICtrlSetOnEventEx(-1, Null, chkMouseEnter) GUISetState() Do Until (GUIGetMsg() = $GUI_EVENT_CLOSE) Func btnMouseClick($iCtrlId) ConsoleWrite("Button clicked..." & @CRLF) EndFunc Func btnMouseEnter($iCtrlId) GUICtrlSetData($iCtrlId, "Enter") EndFunc Func btnMouseLeave($iCtrlId) GUICtrlSetData($iCtrlId, "Leave") EndFunc Func btnMouseDown($iCtrlId) GUICtrlSetData($iCtrlId, "Down") EndFunc Func btnMouseUp($iCtrlId) GUICtrlSetData($iCtrlId, "Button!") EndFunc Func lblMouseEnter($iCtrlId) GUICtrlSetBkColor($iCtrlId, 0xFEFEFE) EndFunc Func lblMouseLeave($iCtrlId) GUICtrlSetBkColor($iCtrlId, 0xEFEFF2) EndFunc Func lblMouseDown($iCtrlId) GUICtrlSetData($iCtrlId, "DOWN") EndFunc Func lblMouseUp($iCtrlId) GUICtrlSetData($iCtrlId, "LABEL") EndFunc Func chkMouseEnter($iCtrlId) Switch ($iCtrlId) Case $chkA ConsoleWrite("Checkbox A hovered...!" & @CRLF) case $chkB ConsoleWrite("Checkbox B hovered...!" & @CRLF) EndSwitch EndFunc Edited March 14, 2014 by D4RKON3 Danyfirex 1 http://faridaghili.ir Link to comment Share on other sites More sharing options...
FaridAgl Posted March 14, 2014 Author Share Posted March 14, 2014 (edited) Example added to the OP. Edited March 14, 2014 by D4RKON3 http://faridaghili.ir Link to comment Share on other sites More sharing options...
FireFox Posted March 14, 2014 Share Posted March 14, 2014 It's a good idea, however it's not reliable with a certain amount of controls. Link to comment Share on other sites More sharing options...
FaridAgl Posted March 14, 2014 Author Share Posted March 14, 2014 FireFox, thanks. Would be nice if you let me know which controls your are referring to. http://faridaghili.ir Link to comment Share on other sites More sharing options...
FireFox Posted March 14, 2014 Share Posted March 14, 2014 Any controls, it's the fact you need to resize the array each time you call the setOnEvent function. It would be better to set a resize step. Link to comment Share on other sites More sharing options...
FireFox Posted March 14, 2014 Share Posted March 14, 2014 But as I can see this one is better than the SetOnEvent by Martin, good job. Link to comment Share on other sites More sharing options...
FaridAgl Posted March 14, 2014 Author Share Posted March 14, 2014 Oh sorry, now I get what you meant. Well, having a lots of registered controls won't cause any problem. As they suppose to be registered only once, the resize would happen once per each event registration. But yes, if you try to frequently register/unregister hundreds of controls during the runtime, it could cause some temporary performance issue, but why should you really do that? Thanks. http://faridaghili.ir Link to comment Share on other sites More sharing options...
FireFox Posted March 14, 2014 Share Posted March 14, 2014 (edited) The example is a custom listview, made with labels. Those items are clickable so they need to be registered. And more the rows you have, more you need to register. But as it's a easy to edit your UDF, don't change anything Edited March 14, 2014 by FireFox Link to comment Share on other sites More sharing options...
FaridAgl Posted March 14, 2014 Author Share Posted March 14, 2014 OK, if you had any improving modification please let me see. Thanks. http://faridaghili.ir Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now