Jump to content
binhnx

Simple and Stupid Control Hover UDF

Recommended Posts

binhnx

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  :rambo:

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  :mad2: . So I wrote an UDF myself, as much simple as possible, and it works out of the box  :dance:

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  :guitar: 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?   :ranting: ) ( 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  :muttley:


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.zip

Edited by binhnx
  • Like 4

99 little bugs in the code

99 little bugs!

Take one down, patch it around

117 little bugs in the code!

Share this post


Link to post
Share on other sites
JScript

Nice! You have some examples to provide us?

SSControlHover_Register($idCtrl, $aIdAttachedCtrl, _
                $fnNormalCb, $vNormalData, $fnHoverCb, $vHoverData, $fnActiveCb, $vActiveData)

Something like popular the sentences below

; #FUNCTION# ====================================================================================================================
; Name ..........: SSControlHover_Register
; Description ...:
; Syntax ........: SSControlHover_Register($idCtrl, $aIdAttachedCtrl, $fnNormalCb, $vNormalData, $fnHoverCb, $vHoverData,
;                  $fnActiveCb, $vActiveData)
; Parameters ....: $idCtrl              - An integer value.
;                  $aIdAttachedCtrl     - An array of unknowns.
;                  $fnNormalCb          - A boolean value.
;                  $vNormalData         - A variant value.
;                  $fnHoverCb           - A boolean value.
;                  $vHoverData          - A variant value.
;                  $fnActiveCb          - A boolean value.
;                  $vActiveData         - A variant value.
; Return values .: None
; Author ........: Your Name
; Modified ......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================

JS

Edited by JScript

http://forum.autoitbrasil.com/ (AutoIt v3 Brazil!!!)

Somewhere Out ThereJames Ingram

somewh10.png

dropbo10.pngDownload Dropbox - Simplify your life!
Your virtual HD wherever you go, anywhere!

Share this post


Link to post
Share on other sites
binhnx

Where's the code?

In the attached file :)


99 little bugs in the code

99 little bugs!

Take one down, patch it around

117 little bugs in the code!

Share this post


Link to post
Share on other sites
pat4005

Thank you very much! I used old UDF by Creator for making GUI "buttons" with Pic controls instead and I've noticed that the state fuctions returns too many results at a time. 'Cause of this I had not critical, but unpleasant blinks on my buttons when push and hold mouse button. Your UDF has solved all the problems. Can you clarify for me more detailed, what Data parameters (like $vClickData) do in your UDF?

P. S. There is a mistake in the _SSCtrlHover_Register function parameters' description. Last two names of parameters duplicating two others above.

Edited by pat4005

Share this post


Link to post
Share on other sites
binhnx

@pat4005: I'm glad you are happy with my UDF :)

Sorry about the description, I wrote it at very late so I almost copy & paste & forget every thing :)

The $vClickData is a variable which then be pass to your $fnClickCb function callback, as like every other $v...Data in my UDF.

I planed to change the UDF a little more (using a fantastic method to store window and control infos so we don't need to loop to find the hover/active... control anymore, and a addtional UDF using the new handy Map feature in new AutoIt version). So I delay changing the description until I finish all the works (I'm too lazy  :sweating: ) (Currently I have no time for it :sweating: , but I will begin as soon as possible, so just wait  :thumbsup: )


99 little bugs in the code

99 little bugs!

Take one down, patch it around

117 little bugs in the code!

Share this post


Link to post
Share on other sites
pat4005

binhnx, hi. Not so long ago I've had a problem with your UDF. When I point "-1" value as a first parameter in _SSCtrlHover_Register function then nothing works. I need to use a variable with control id instead. Also when I use _SSCtrlHover_Register function in multiple places in my program (in multiple windows) some of buttons work and some don't. Can you explain such behavior? Unpatiently wait for a new version of your UDF anyway!

Edited by pat4005

Share this post


Link to post
Share on other sites
binhnx

At line 67:

$_aControlHoverData[$iIndex][0] = $idCtrl

I forgot to check $idCtrl = -1 at that point. You can modify it by adding this line after line 57 (before WinAPI GetAncestor() call)

If ($idCtrl=-1) Then $idCtrl = DllCall("user32.dll", "INT", "GetDlgCtrlID", "HWND", $hWnd)[0]

Sorry about that odd bug. I'll fix it in new version.

About the second bug, I haven't pointed out what wrong yet. Currently, my script only working with controls inside top-level GUI. If you use with nested GUI (child GUI(s) created by specified $WS_CHILD in GUICreate), you may get unexpected behavior. I'm not sure if that is your problem or not.

When I wrote the first line of the UDF, I decided that it should be much AutoIt as possible. So I try to reduce any WinAPI call (by DllCall), callback or timer function. But as time go by, I realize that it's impossible to write a good UDF without using many WinAPI functions :) This will solve a lot of problems with current version.

Good news: Will start writing today. You may have the new version tomorrow :D

Edited by binhnx

99 little bugs in the code

99 little bugs!

Take one down, patch it around

117 little bugs in the code!

Share this post


Link to post
Share on other sites
pat4005

binhnx, your work is impressively REMARKABLE! Of course, I've already downloaded and tested new v3 UDF and it works perfectly great. To be more specific I've noticed speed improvement even by eye, my former problem was just miraculously solved and however blinking defect is still absent. Thank you very much!:thumbsup: But here is some "but". I found a little problem and I want to ask you some other questions:

1) Problem is that when I try to exit script containing your UDF functions using HotKeySet function for that, it crushes with an AutoIt big-don't-know-how-to-call-it error twice. Other times all works well.

 

2) Why don't you put your Assert function inside UDF?
3) Whether еру hover button effect must work when GUI is not active (just curious)?
4) Can you please post an example which will contain ready to use and clickable "button on hover" working scheme with images on controls (if I expressed my thoughts correctly)?
 
UPD: When compiled script crushes after any way to exit it  :ermm:.
Edited by pat4005

Share this post


Link to post
Share on other sites
binhnx

@pat4005:

1. About the crash problem: I'll fix it later. But it's a good practice to manually delete all the GUI  (using GUIDelete) before using the Exit function.

2. Assert function is used for all my UDF so I think it's better to separate it to a different file. If you find it annoying and you only use this UDF, copy that function to main UDF file.

3. The event is delivered by Windows directly, so the hover function is called exactly when a control is on hover, and the normal function is called exactly when the mouse leave the control. Don't worry, it works no matter your GUI is activated or not. It only not work when your GUI is minimized or hidden (why do you need it to work when you can not put your mouse over the control :) ) It works when you need it and doesn't work when you don't need to save your CPU :) )

4. Later, later, later. I'll add a addition SSButtonHover UDF. Now I'm messing with another project :D

Edit: Assert is intended to use in dev. It's only mission is check for something that may cause if you write something careless. So, if you're sure all things you wrote a right: check error, ensure the variable type you specified is match with the expected type... so you definitely safe to remove all the assert statement from my UDF.

PS: Thank you for your feedback, it helps me a lot to improve my UDF quality.

Edited by binhnx

99 little bugs in the code

99 little bugs!

Take one down, patch it around

117 little bugs in the code!

Share this post


Link to post
Share on other sites
pat4005
binhnx, I got it. There is more about your UDF. After using hovering image onto pic control I've saw image lags similar to those that was with using Creator's UDF. Is it a known bag?

Share this post


Link to post
Share on other sites
Yashied
ura

Great job :D

Share this post


Link to post
Share on other sites
ura

How to make click and double click trigger different mouse event ?

Share this post


Link to post
Share on other sites
ura

Hi

About the crash problem Is there a better way?-_-

Share this post


Link to post
Share on other sites
ura
8 hours ago, Jos said:

哪个崩溃的问题?你确实意识到你在一个3年的线程发布?

乔斯

Hi, Jos.

1) Compile and run in the exit when there will be two prompt error (The reason seems to be that the registered subclasses have not been removed)

2) I need this udf, and in improving this UDF, help me:unsure:

 

Share this post


Link to post
Share on other sites
LarsJ

It's true that the crash during script end when the script is run as 64-bit code is caused by the subclasses have not been removed.

You can remove the subclasses in the example in the first post in this way:

#AutoIt3Wrapper_UseX64=y

#include "SSCtrlHover_v3.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

_WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($idLbl1), $__SSCTRLHOVER_PSUBCLASSEXE, GUICtrlGetHandle($idLbl1))
_WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($idLbl2), $__SSCTRLHOVER_PSUBCLASSEXE, GUICtrlGetHandle($idLbl2))

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

 

  • Like 1

Share this post


Link to post
Share on other sites
ura
On 2017-4-19 at 0:03 AM, LarsJ said:

确实,当脚本运行时,脚本中的崩溃是64位代码由子类引起的还没有被删除。

您可以通过以下方式删除第一篇文章中示例中的子类:

#AutoIt3Wrapper_UseX64 = Y

#include “SSCtrlHover_v3.au3

GUICreate@AutoItVersion$ idLbl1  =  GUICtrlCreateLabel(“标记1” , 55 ) 
SSCtrlHover _寄存器($ idLbl1 , “FnNormal” , 0 , “FnHover” , 0 , “FnActive” , 0 , “FnClick” , 0$ idLbl2  = GUICtrlCreateLabel(“Label 2” , 535 ) 
SSCtrlHover _ Register($ idLbl2 , “FnNormal” , 0 , “FnHover” , 0 , “FnActive” , 0 , “FnClick” , 5GUISetState()

而 GUIGetMsg() <>  - 3 
  睡眠(10WEnd

_WinAPI_RemoveWindowSubclassGUICtrlGetHandle$ idLbl1 ), $ __ SSCTRLHOVER_PSUBCLASSEXE , GUICtrlGetHandle$ idLbl1 ))
_WinAPI_RemoveWindowSubclassGUICtrlGetHandle$ idLbl2 ), $ __ SSCTRLHOVER_PSUBCLASSEXE , GUICtrlGetHandle$ idLbl2 ))

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

 

How to integrate into the UDF?

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Similar Content

    • caramen
      By caramen
      I watched _OL_ItemSend&_OL_ItemFind&_OL_ItemCreate in OutlookEx UDF but hmmm
       
      Since it use the test environnement i cant get the orders of the mail creation
       
      Can someone make me win some time of reading all exemples script and lead me how to do one ?
      That whould be lovely.
      Gnight
    • Tersion
      By Tersion
      Here the this wiki page with list of available UDFs for data compression. For my tasks I only need ZIP support, so I started looking at pure AutoIt UDFs without any 3rd party dlls. And found out that most of available realizations uses standard ("native method") Windows dll - "zipfldr.dll". So for now I chose ZIP UDF by wraithdu. I've tested it on Windows 7 (x64) and it seem works fine. But here the comment from another topic where user says that Windows 10 discontinued support of "zipfldr.dll". Now I confused. I don't have around any Windows 10 machine to tested it. So maybe someone could confirm or deny that? Or maybe would better to switch to UDF with 7zip dll?
      I need an advice...
    • TheSaint
      By TheSaint
      Here is the bare bones of a UDF I have started work on.
      Mostly just a proof of concept at this stage, and still need to add some functions and dress the UDF up a bit ... to look like a UDF ... though it has my own distinct styling, especially as I have never really developed a UDF before now .... used plenty and modified plenty though. I've even invented my own UDF variable naming convention, which I am sure some of you will be aghast at. I work with what feels best for me, but others are free to adapt if they wish.
      The idea is to emulate the simplicity of INI files, but gain the benefits of SQL.
      Two scripts are provided.
      (1) The UDF, a work in progress - SimpleSQL_UDF.au3
      (2) An example or testing script - UDF_Test.au3
      Another first for me, is creating a 2D array from scratch, never done that before, that I can recall ... never had a need, and even for 1 dimension arrays, for a long time now, I have just used _StringSplit to create them. So I needed a bit of a refresher course, which my good buddy @TheDcoder assisted me with ... not without some angst I might add. LOL
      SimpleSQL_UDF.zip  (12 downloads previously)
      (I have now completed all the functions I intended to. My next update will be a big improvement, bringing things more inline with my latest INItoSQL DB program changes.)
      Program requires the sqlite3.dll, not included, but easily enough obtained.
      Hopefully the usage is self-evident ... just change the Job number variable in the UDF_Test.au3 file to check the existing functions out.
      Enjoy!
      P.S. This is also related to a new program I have just finished and uploaded - INItoSQL DB
    • xtcislove
      By xtcislove
      Hello,
      as a start in Autoit i tried something i was missing since im using Autoit. 

      I build a custom MessageBox which has a large amount of custom options and which scales its size on the parameters you set. 

      Aviable Settings:
      -Title
      -Unlimited Buttons
      -Text Color (Buttons, Text)

      -Background Color (Msgbox, Buttons, Label) 

      -Button Timeout
      -Autoclose Timeout
      -Icon (Default, No Icon, Custom)

      -Label/ Button Style. 
      -Transparency

      I tried to keep this as close as i could to a Msgbox i was used too on my batch times.

      After i was ready i realised, @Melba23 probably build a way better msgbox which would have suit my needs enterly, anyway thanks to @Melba23 because i use his Stringsize UDF. 

       
       
      local $Message = _sMsgBox("Test", 6, "Continue?") if @extended <> -1 Then MsgBox(0, @extended, $Message&" Button pressed")  
      ScalingMessageBox.au3
    • Gowrisankar
      By Gowrisankar
      Dear members, 
      I am working on a project where, emails from outlook are to be read and moved to various folders within the mailbox, based on the content of the emails.
      I used the below code for moving mails. It works fine when I run it against individual mail ids. But when I run it on Shared mailbox, the mails are not moved to respective folders.
      _OL_ItemMove($oOutlook, $sEntryId, Default, $sDestinationFolder) The value of $sEntryId is saved in an excel report initially. The current process reads the $sEntryId from the excel and passes it to "_OL_ItemMove" statement.
      Requesting the guidance of the forum members in this issue.
×