Leaderboard
Popular Content
Showing content with the highest reputation on 04/15/2017 in all areas
-
Simple and Stupid Control Hover UDF
boomingranny reacted to binhnx for a topic
Version 3: Ops, you may ask, where's the version 2? The answer is, you will never see it. I skipped it to jump to version 3 directly. Why? Actually, I didn't learn M$ about that versioning The reason is, I planed to write version 2, using the new window/control handle indexing technique to eliminate all the ugly and slow loop. But when nearly finish, I feel so tired, tired of using a lots of all workaround. And finally, I decided to rewrite entire the UDF, using the direct solution, the way all other languages used, and should use. I late some day, because of some machine code (it's actually not so necessary, but if the control is doing an expensive task, like heavy drawing then passing all the Window Message to AutoIt is not a so good idea because its slow speed may result in some annoying-small-but-easy-to-figure-out problems, (like tearing as example). So I use machine code directly to pass over it. Now you have not a Stupid but a Smart UDF And it's still simple. API change: Remove a parameter from _SSCtrlHover_Register. You nolonger can attach other controls to the registered control. Use another method to do it and when you delete the control be sure to delete all the attached controls yourself. This breaks your old script. Add double click event (last 2 parameters of _SSCtrlHover_Register) Remove the _SSCtrlHover_Delete. You must manually delete yourself. It's easy with GUICtrlDelete and I decide not to duplicate this function to my UDF (be sure to delete your attached control too) This version eliminate all the odd limit of old version, include: No:longer use timer/adlib to test the control is on mouse event. Now it directly use native WinAPI method to provide a truly event-driven way. Every click is detected, every mouse hover/left, is handled perfectly. Fast and very fast. All the loop is eliminated. Machine code. Execute speed is much much improved. (read as: nano seconds instead of milliseconds ) I documented it quite well so if you want you can easily browse it and change it the way you want. Now you can use in both GUIGetMsg() loop mode or event mode. No longer setting constants like before because it works perfectly in both mode. Cheer Remark: I don't include <WinAPI.au3> and <WinAPIShellEx.au3> in my UDF, because those UDF is very large and it will consume much more memory when you run (not matter you run the 'compiled' exe, the au3 file, or the .a3x file). In the CtrlHover UDF, i included a small subset of those UDF with the same name, so if you have already included <WinAPI.au3> or <WinAPIShell.au3>, be sure to edit the UDF and comment out the corresponding region. Edit 2: Reorganize script. Fix some issues when drag too fast. Add ability to handle "click" (work RIGHT as normal button, will not fire if you only release the mouse button upon the control as some UDF use MouseUp event) Add a helper method to check if MouseUp event is click event or not. Add compability function to call as normal UDF (with first letter is underscore). Edit 1: Add some function descriptions as JS's advice. Thank you I also changed script name (shorter) and modify the register function so it may be called with less parameter. From now on, the function name and calling syntax will be fixed. OK, I know there is the famous "GUICtrlOnHover" UDF already in this forum, and many people have used it and enjoyed it! But the UDF didn't work as I expected . So I wrote an UDF myself, as much simple as possible, and it works out of the box It has some advantages compare to the old GUICtrlOnHover.au3 It creates the normal button behavior. When you press primary mouse button in the control and begin to drag, it do not set other controls to "hover" state. Faster. I try to add 2k controls. When mouse change from one control to another, it only take about 25ms to handle. In idle state (mouse cursor is not over any control), the cost is ignorable with < 0.1ms. Compare with GUICtrlOnHover UDF takes about 3ms when mouse cursor is over the control, but in idle state, it takes about 35ms. (I do not know why) (That is, because I tested script with overlapped controls. GUICtrlOnHover rely on WinAPI function WindowFromPoint(), which return the first created control (the control with is overlapped any others), but my script rely on GUIGetCursorInfo() which return the last created control - which is the most nested control in Windows). So my script need to check entire 2k control, but GUICtrlOnHover return the first element. I will wait for information about GUIGetCursorInfo() to decide that my UDF should use WinAPI function instead of the native function. In the normal usecase and controls is not overlapped, my UDF is far faster. Edit: Add a setting constant, make you ability to choose use WindowFromPoint() or GUIGetCursorInfo(). Default to the WinAPI function) Faster time to create/ register control. Native AutoIt. No Callback. The only DllCall I use is to get parent window of a control. Wonder why AutoIt do not have a similar function. Found a new bug #2899. If someone can ad more functinal to WinGetHandle("[LAST]"), it should be great Edit: Use some other WinAPI call to provide workaround for issue with GUIGetCursorInfo. Smaller size, about 280 lines compare with about 400 lines of GUICtrlOnHover. More simple, more easy to use. No more than 120 characters in one line. No annoying jumping when scroll the UDF Support event mode to detect mouse down event. But it doesn't work with overlay control. So you cannot have a control (with event) over another control. (use $_BGUIGETCURSORINFOFIX const setting to get rid of this). It seems that it's a AutoIt bug, the GUIGetCursorInfo return a useless control id when controls overlapped. Its not the same with the control received with WindowFromPoint(), or the control which fire event (anyone can confirm it's a bug? Or it's a special feature? ) ( I open a new Trac Ticket here: #2900) Current limit: Mouse down Almost all mouse event is currently detected by timeout (this is why the script called Simple and Stupid, but every UDF I found in this forum also use this method). You can set a smaller timeout to catch the mouse, but sometimes its annoying. Edit: Default changed to 30ms timeout, it should be fast enough to detect any click! You can also change to use event mode to detect click better! Otherwise, it works like a charm. Try it and happy with it Example: Callback function #include "SSCtrlHover.au3" GUICreate(@AutoItVersion) $idLbl1 = GUICtrlCreateLabel("Label 1", 5, 5) SSCtrlHover_Register($idLbl1, "FnNormal", 0, "FnHover", 0, "FnActive", 0, "FnClick", 0) $idLbl2 =GUICtrlCreateLabel("Label 2", 5, 35) SSCtrlHover_Register($idLbl2, "FnNormal", 0, "FnHover", 0, "FnActive", 0, "FnClick", 5) GUISetState() While GUIGetMsg() <> -3 Sleep(10) WEnd Func FnNormal($idCtrl, $hWnd, $vData) ConsoleWrite(@CRLF & "Normal/Leave " & $idCtrl) EndFunc Func FnHover($idCtrl, $hWnd, $vData) ConsoleWrite(@CRLF & "Hover " & $idCtrl) EndFunc Func FnActive($idCtrl, $hWnd, $vData) ConsoleWrite(@CRLF & "Active " & $idCtrl) EndFunc Func FnClick($idCtrl, $hWnd, $vData) ConsoleWrite(@CRLF & "CLICK! " & $idCtrl & " - " & $hWnd & " - " & $vData) EndFunc You can use it with GUICtrlSetImage to provide a "hover button" effect Version 1: SSCtrlHover.au3 Version 3: SSCtrlHover.zip1 point -
Thanks, you explained it a lot better than I did.1 point
-
I apologise @czardas for hijacking this thread, but thought I would clear a few things up ... I am not working on a new version of the Help File, as the current one seems just fine to me My opinions about Local being used in the help files still stand as correct, especially when you look at it from the point of view that the variable(s) are "local to the scope" i.e. imagine that big space outside of all the functions defined, is wrapped in an imaginary Main function. Since the likes of C/C++/C# require a function entry point normally labelled "main" ; This line is used elsewhere Global $sGlobalVar = '' ; This line can be seen as ... Local $sLanguage = 'JavaScript' ; ... this line, since the variable is not used anywhere else Func Main() Local $sLanguage = 'JavaScript' ConsoleWrite($sLanguage) EndFunc Function SomeOtherFunc() $sGlobalVar = 'A truly globally variable' EndFunc Disclaimer: I am mainly using JavaScript these days anyway, in which I have created my own Promise and Observable polyfills, plus I use the highly respected Airbnb Style Guide for writing clean and understandable JavaScript.1 point
-
Deye, That is essentially what the UDF does already so I have no idea what you mean. Each section must have its own controls (which must have their ControlIDs stored in separate variables) created between _Section_Create calls (rather like when creating tabs) and only the visible ones can be actioned. In the script you posted the radio controls share either coordinates or ControlID variables - how on earth do you expect the UDF to sort out what you want to do? What I suggest is to create the whole GUI at maximum size (i.e. all section expanded) with all its controls (for all sections) first and then create the sections by inserting the _Section_Create calls at the appropriate places - that way you get all the controls in the correct sections. Perhaps if you tried that way of constructing your GUI you would have fewer problems? I see the interest in using the previous section position as used in the UDF to create the controls - but doing as I explained above removes the necessity to do so as you create the entire GUI before the sections. However, let me have a think about how such a thing might be implemented without causing too many script-breaking changes to the current UDF. I will also take a look at the script you posted to see if I can get it to work as I think you wish it behave. M23 Edit: That was one seriously messed up attempt to use the UDF - did you actually look at any of the examples? This seems to work: #include <GUIConstantsEx.au3> #include "GUIExtender.au3" $hGUI = GUICreate("Parent GUI", 340, 360) ;~ _GUIExtender_Init($hGUI) _GUIExtender_Init($hGUI, 0, 0, True) ; This section starts at 0 and is 90 pixels deep $iSection_1 = _GUIExtender_Section_Create($hGUI, -1, 90) $Button = GUICtrlCreateButton(Chr(0x71), 208, 10, 115, 25, 0, 1) GUICtrlSetFont(-1, 10, 600, -1, "WingDings 3") $Label1 = GUICtrlCreateLabel("first-section", 216, 48, 70, 19) ;$iSection_2 = _GUIExtender_Section_Create($hGUI, 90, -1) ; You are asking the UDF to create this section starting at 90 and fill the remainder of the GUI $iSection_2 = _GUIExtender_Section_Create($hGUI, -1, 90) ; Now you are askign for a 90 pixel section to follow on from the previous $Radio1 = GUICtrlCreateRadio("_Section_2.1", 170, 104, 89, 25) ; So these must be within the y coord range 90-180 - which they are $Radio2 = GUICtrlCreateRadio("_Section_2.2", 170, 126, 89, 25) $Radio3 = GUICtrlCreateRadio("_Section_2.3", 170, 148, 89, 25) GUICtrlSetState(-1, $GUI_CHECKED) ; You also need to activate the section _GUIExtender_Section_Activate($hGUI, $iSection_2) ; Now the section can be activated programatically by the button ;$iSection_3 = _GUIExtender_Section_Create($hGUI, 90, 160) ; you are sking this section to begin at 90 (which is where the previous started so the call will error $iSection_3 = _GUIExtender_Section_Create($hGUI, -1, 160) ; Now you will have section starting after the previous (180) and 160 deep ;$Radio4 = GUICtrlCreateRadio("_Section_3", 170, 104, 89, 25) ; So these are not within the section boundaries (180-340) and will not be recognised by the UDF ;$Radio5 = GUICtrlCreateRadio("_Section_3", 170, 136, 89, 25) ;$Radio6 = GUICtrlCreateRadio("_Section_3", 170, 168, 89, 25) $Radio4 = GUICtrlCreateRadio("_Section_3.1", 170, 204, 89) $Radio5 = GUICtrlCreateRadio("_Section_3.2", 170, 226, 89) $Radio6 = GUICtrlCreateRadio("_Section_3.3", 170, 248, 89) ; You also need to activate this sectiontoo _GUIExtender_Section_Activate($hGUI, $iSection_3) ; These need to be created in the section which will hold them, so I have moved them there Global $cInput = GUICtrlCreateInput("0", 92, 238, 10, 17) Global $cUpDown_Min = GUICtrlCreateUpdown($cInput) Global $cTimer_Label = GUICtrlCreateLabel("12", 56, 240, 30, 15) ; $iSection_4 = _GUIExtender_Section_Create($hGUI, 160, -1) ; Again you are asking the section to start in the wrong place which will error $iSection_4 = _GUIExtender_Section_Create($hGUI, -1, -1) ; All you can do is to ask it fill the remaoining space - all 20 pixels of it!!! ;$Radio4 = GUICtrlCreateRadio("_Section_4", 170, 204, 89, 25) ; And again these are outside the section boundaries (340-360) ;$Radio5 = GUICtrlCreateRadio("_Section_4", 170, 236, 89, 25) ;$Radio6 = GUICtrlCreateRadio("_Section_4", 170, 268, 89, 25) $Radio7 = GUICtrlCreateRadio("_Section_4.1", 170, 340, 89, 20) ; This ection is not sctivated and so will remain static under whichever of 2 or 3 is showing _GUIExtender_Section_Create($hGUI, -99) ; And you never close the section definiton ; So where are these supposed to be? Looking at the coordinate they should be in Section 3, so put them there ;Global $cInput = GUICtrlCreateInput("0", 92, 238, 10, 17) ;Global $cUpDown_Min = GUICtrlCreateUpdown($cInput) ;Global $cTimer_Label = GUICtrlCreateLabel("12", 56, 240, 30, 15) GUISetState(@SW_SHOW) ;~ _GUIExtender_Section_Action($hGUI, $iSection_2, True) _GUIExtender_Section_Action($hGUI, $iSection_3, 0, 9) ; Closing section 3 ;_GUIExtender_Section_Action($hGUI, $iSection_4, 0, 0) ; This section is static so no point While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit Case $Button ;MsgBox(0, _GUIExtender_Section_State($hGUI, $iSection_2), 'here it is showing as static - return of - 2') ; of course becasue you never activated it ;If _GUIExtender_Section_State($hGUI, $iSection_2) = 2 Then ; _GUIExtender_Section_Action($hGUI, $iSection_2, False) ; _GUIExtender_Section_Action($hGUI, $iSection_3, True) ;Else ; _GUIExtender_Section_Action($hGUI, $iSection_3, False) ; _GUIExtender_Section_Action($hGUI, $iSection_2, True) ;EndIf ; just toggle the sections _GUIExtender_Section_Action($hGUI, $iSection_2, 9) _GUIExtender_Section_Action($hGUI, $iSection_3, 9) EndSwitch WEnd Does that make it clearer?1 point
-
Two scripts at the same time
Cryofus reacted to DarkDragon for a topic
I know how to send strings to a program with ControlSend(), but in my opinion there isn't a function to send mouse movements to a windows in background. I'm sorry but I can't help you.1 point -
I think topic about answer is going out of the scope (no variables one haha) Because answer is already answered. If were talking about an answer. czardas's one is clear and correct at least for me. the one with ternary operator is correct too. But We're no talking about make our code shorter. talking about out topic (variable scope) I usually do something like this. ;~ when I do Scripts with many functions I put all my global variables at script's top with the Global keyword. #Region Sample-1 Global $g_sSomething="Something" ;do something here Func _Func1() ;probably use my $g_sSomething EndFunc Func _Func2() ;probably use my $g_sSomething Local $sSomething="Something local here" ;similar name as global one but using variable naming EndFunc #EndRegion ;But when I create Scripts (usally small scripts) without functions(Predefined) I use always Local keyword #Region Sample-2 local $g_sSomething="Something" ConsoleWrite($g_sSomething & @CRLF) #EndRegion Saludos1 point
-
If you say that 3 times into a silvered mirror then @guinness will appear and smite you.1 point
-
Quite funny . I prefer to do it right when I do it, no matter how small "it" is .1 point
-
Declaring variables Local at the top of the script could be misleading for beginners "If you declare a variable at the start of your script and outside any functions it exists in the global scope" (help file) Indeed it does, regardless of the declared scope And "You can also assign a variable without declaring it first" (help file) ;Local $txt = "test" ; works ;Global $txt = "test" ; works $txt = "test" ; works Display() Func Display() Msgbox(0,"", $txt) ; $txt always exists in a global scope EndFunc All are allowed and correct - and a priori conform to good coding practices1 point
-
GuiExtender problem
antonioj84 reacted to Melba23 for a topic
antonioj84, 1. You forgot the line to disable the coloured label, so none of the other controls will work as AutoIt cannot tell which overlapped control you wish to action. 2. Just add them within the section creation structure as I have done in the amended example below. 3. You were reusing the same variable names that you used in the Blue section to store the ControlIDs for the controls in Green section. Hence you overwrote the Blue values and they no longer work. Just use different variable names - again as in the script below. 4. Just look for the ControlIDs as normal. Guess what? The example below shows you how to do it: #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <ButtonConstants.au3> #include <ComboConstants.au3> #include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> #include <MsgBoxConstants.au3> #include "GUIExtender.au3" ; Create parent GUI $hGUI = GUICreate("Store Build", 1000, 300) GUISetState(@SW_HIDE, $hGUI) ; Create sections in main GUI _GUIExtender_Init($hGUI, 1) $iSection_1 = _GUIExtender_Section_Create($hGUI, 0, 500) GUICtrlCreateLabel("", 0, 0, 500, 300) GUICtrlSetBkColor(-1, 0xCCCCFF) GUICtrlSetState(-1, $GUI_DISABLE) ; You need to disbale the lable - you forgot to move that line <<<<<<<<<<<<<<<<<<<<< ; Add some controls so we can see which section is which $Group1 = GUICtrlCreateGroup("POS", 16, 8, 177, 49) $Radio1 = GUICtrlCreateRadio("Fixed", 32, 32, 65, 17) $Radio2 = GUICtrlCreateRadio("Tablet", 120, 32, 65, 17) GUICtrlCreateGroup("", -99, -99, 1, 1) $hCombo = GUICtrlCreateCombo("", 304, 80, 37, 25, BitOR($CBS_DROPDOWN,$CBS_AUTOHSCROLL)) GUICtrlSetData(-1, "");"sList1") $Setting = GUICtrlCreateButton("Setting", 80, 224, 65, 25) $Exit = GUICtrlCreateButton("Exit", 392, 224, 65, 25) $Button3 = GUICtrlCreateButton("Expand", 8, 224, 65, 25) $Input1 = GUICtrlCreateInput("", 208, 80, 57, 24) GUICtrlSetLimit(-1,4) ; to limit the entry to 3 chars GUICtrlSetTip(-1, "Enter Store Number") $RE = GUICtrlCreateLabel("RE", 272, 80, 22, 24, $SS_SUNKEN) $SREI = GUICtrlCreateLabel("SREI", 168, 80, 35, 28, BitOR($SS_CENTER,$SS_SUNKEN)) $Start = GUICtrlCreateButton("Start", 200, 120, 97, 33) _GUIExtender_Section_Activate($hGUI, $iSection_1 + 1, "", "", 470, 10, 20, 20) ; Create a button to action programatically a section of another GUI $cSect_4 = GUICtrlCreateButton("Section 4", 10, 270, 80, 30) $iSection_2 = _GUIExtender_Section_Create($hGUI, 500, 500) GUICtrlCreateLabel("", 500, 0, 500, 300) GUICtrlSetBkColor(-1, 0xFFCCCC) GUICtrlSetState(-1, $GUI_DISABLE) GUICtrlCreateLabel("I am the PINK section that opens and closes", 500, 100, 300, 20) ; Add a control in the pink section <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $cPink_Button = GUICtrlCreateButton("Pink Test", 510, 10, 80, 30) ; Close section creation structure _GUIExtender_Section_Create($hGUI, -99) ; Create and position child GUI $aGUI_Pos = WinGetPos($hGUI) $hGUI_Child = GUICreate("Follower", 500, 200, 0, 0, BitOR($WS_POPUP, $WS_BORDER), 0, $hGUI) WinMove($hGUI_Child, "", $aGUI_Pos[0], $aGUI_Pos[1] + $aGUI_Pos[3]) GUISetState(@SW_HIDE, $hGUI_Child) ; Create section sin child GUI _GUIExtender_Init($hGUI_Child) $iSection_3 = _GUIExtender_Section_Create($hGUI_Child, 0, 1) ; I am the RED section that is static GUICtrlCreateLabel("", 0, 0, 500, 1) GUICtrlSetBkColor(-1, 0xFF0000) GUICtrlSetState(-1, $GUI_DISABLE) $iSection_4 = _GUIExtender_Section_Create($hGUI_Child, 1) GUICtrlCreateLabel("", 0, 1, 500, 200) GUICtrlSetBkColor(-1, 0xCCFFCC) GUICtrlSetState(-1, $GUI_DISABLE) GUICtrlCreateLabel("I am the Green section that opens and closes", 0, 100, 300, 20) ; Activate this section with no visible button _GUIExtender_Section_Activate($hGUI_Child, $iSection_4) ; Close section creation structure _GUIExtender_Section_Create($hGUI_Child, -99) ; Close extendable sections _GUIExtender_Section_Action($hGUI, $iSection_2, False) _GUIExtender_Section_Action($hGUI_Child, $iSection_4, False) ; And display the GUI(s) $Child_Group1 = GUICtrlCreateGroup("POS", 16, 8, 177, 49) ; You must use different variables to store the ControlIDS or you overwrite the earlier controls <<<<<<<<<<<<<<< $Child_Radio1 = GUICtrlCreateRadio("Fixed", 32, 32, 65, 17) $Child_Radio2 = GUICtrlCreateRadio("Tablet", 120, 32, 65, 17) GUICtrlCreateGroup("", -99, -99, 1, 1) $hChild_Combo = GUICtrlCreateCombo("", 304, 80, 37, 25, BitOR($CBS_DROPDOWN,$CBS_AUTOHSCROLL)) GUICtrlSetData(-1, "");"sList1") $Child_Setting = GUICtrlCreateButton("Setting", 80, 224, 65, 25) $Child_Exit = GUICtrlCreateButton("Exit", 392, 224, 65, 25) $Child_Button3 = GUICtrlCreateButton("Expand", 8, 224, 65, 25) $Child_Input1 = GUICtrlCreateInput("", 208, 80, 57, 24) GUICtrlSetLimit(-1,4) ; to limit the entry to 3 chars GUICtrlSetTip(-1, "Enter Store Number") $Child_RE = GUICtrlCreateLabel("RE", 272, 80, 22, 24, $SS_SUNKEN) $Child_SREI = GUICtrlCreateLabel("SREI", 168, 80, 35, 28, BitOR($SS_CENTER,$SS_SUNKEN)) $Child_Start = GUICtrlCreateButton("Start", 200, 120, 97, 33) GUISetState(@SW_SHOW, $hGUI) GUISetState(@SW_SHOW, $hGUI_Child) ; Look for the main GUI moving GUIRegisterMsg($WM_MOVE, "_WM_MOVE") ; how do i access the control $iMsg from each 3 menu ; Just as you would normally <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< While 1 $iMsg = GUIGetMsg() Switch $iMsg Case $GUI_EVENT_CLOSE Exit Case $cSect_4 ; Toggle the section in the child GUI programatically _GUIExtender_Section_Action($hGUI_Child, $iSection_4, 9) Case $Start MsgBox($MB_SYSTEMMODAL, "Hi", "Start button in blue section pressed") Case $Child_Start MsgBox($MB_SYSTEMMODAL, "Hi", "Start button in green section pressed") Case $cPink_Button MsgBox($MB_SYSTEMMODAL, "Hi", "Test button in pink section pressed") EndSwitch ; Pass main GUI handle and event message to the UDF so it can action its extendable section automatically _GUIExtender_EventMonitor($hGUI, $iMsg) WEnd Func _WM_MOVE($hWnd, $iMsg, $wParam, $lParam) ; If the main GUI moves If $hWnd = $hGUI Then ; Move the child to follow Local $aGUI_Pos = WinGetPos($hWnd) WinMove($hGUI_Child, "", $aGUI_Pos[0], $aGUI_Pos[1] + $aGUI_Pos[3]) EndIf EndFunc ;==>_WM_MOVE Look for the <<<<<<< lines. M231 point