Add Image Mouseover effect in AutoHotkey GUI

 Couldn't find this anywhere on the net and kinda needed it so am making a note of how to do it here.

The issue is that I wanted to make my autohotkey program change the image that the mouse hovers over (within it's own GUI).  No third-party component or dll needed, just a slight modification to the mousemove tooltip in the autohotkey manual.

 The following code is not the whole code or a working program but should demonstrate how to include it in your own Autohotkey GUI:

copyraw
; SET TOOLTIP TEXT
    SearchButton_TT:="Search"

    ; SHOW THE GUI
    Gui, Add, Button, x575 y40 w85 h85 +Default +gSearch +Hide, Search
    Gui, Add, Picture, x573 y40 w93 h96 vSearchButton gSearch, %A_ScriptDir%\search_globe.jpg
    Gui, Add, Edit, x45 y40 w520 r1 vSearchTextInput Limit70, Search...
    Gui, Show
    OnMessage(0x200, "WM_MOUSEMOVE")
    Return


    ; FUNCTION TO HANDLE BOTH TOOLTIP AND MOUSEOVER EVENT
WM_MOUSEMOVE()
{
    static CurrControl, PrevControl, _TT  ; _TT is kept blank for use by the ToolTip command below.
    CurrControl := A_GuiControl

    SearchButton_Over:=A_ScriptDir "\images\program\icons\search_globe_over.png"
    SearchButton_Out:=A_ScriptDir "\images\program\icons\search_globe.png"

    If (CurrControl <> PrevControl and not InStr(CurrControl, " "))
    {
        ToolTip  ; Turn off any previous tooltip.
        SetTimer, DisplayToolTip, 1000
        If (PrevControl="SearchButton")
            GuiControl,, SearchButton, %SearchButton_Out%

        PrevControl := CurrControl
        If (CurrControl="SearchButton")
            GuiControl,, SearchButton, %SearchButton_Over%
    }
    return

    DisplayToolTip:
    SetTimer, DisplayToolTip, Off
    ToolTip % %CurrControl%_TT  ; The leading percent sign tell it to use an expression.
    SetTimer, RemoveToolTip, 3000
    return

    RemoveToolTip:
    SetTimer, RemoveToolTip, Off
    ToolTip
    return
}

Search:
Return

GuiClose:
ExitApp
  1.  ; SET TOOLTIP TEXT 
  2.      SearchButton_TT:="Search" 
  3.   
  4.      ; SHOW THE GUI 
  5.      Gui, Add, Button, x575 y40 w85 h85 +Default +gSearch +Hide, Search 
  6.      Gui, Add, Picture, x573 y40 w93 h96 vSearchButton gSearch, %A_ScriptDir%\search_globe.jpg 
  7.      Gui, Add, Edit, x45 y40 w520 r1 vSearchTextInput Limit70, Search... 
  8.      Gui, Show 
  9.      OnMessage(0x200, "WM_MOUSEMOVE") 
  10.      Return 
  11.   
  12.   
  13.      ; FUNCTION TO HANDLE BOTH TOOLTIP AND MOUSEOVER EVENT 
  14.  WM_MOUSEMOVE() 
  15.  { 
  16.      static CurrControl, PrevControl, _TT  ; _TT is kept blank for use by the ToolTip command below. 
  17.      CurrControl := A_GuiControl 
  18.   
  19.      SearchButton_Over:=A_ScriptDir "\images\program\icons\search_globe_over.png" 
  20.      SearchButton_Out:=A_ScriptDir "\images\program\icons\search_globe.png" 
  21.   
  22.      If (CurrControl <> PrevControl and not InStr(CurrControl, " ")) 
  23.      { 
  24.          ToolTip  ; Turn off any previous tooltip. 
  25.          SetTimer, DisplayToolTip, 1000 
  26.          If (PrevControl="SearchButton") 
  27.              GuiControl,, SearchButton, %SearchButton_Out% 
  28.   
  29.          PrevControl := CurrControl 
  30.          If (CurrControl="SearchButton") 
  31.              GuiControl,, SearchButton, %SearchButton_Over% 
  32.      } 
  33.      return 
  34.   
  35.      DisplayToolTip: 
  36.      SetTimer, DisplayToolTip, Off 
  37.      ToolTip % %CurrControl%_TT  ; The leading percent sign tell it to use an expression. 
  38.      SetTimer, RemoveToolTip, 3000 
  39.      return 
  40.   
  41.      RemoveToolTip: 
  42.      SetTimer, RemoveToolTip, Off 
  43.      ToolTip 
  44.      return 
  45.  } 
  46.   
  47.  Search: 
  48.  Return 
  49.   
  50.  GuiClose: 
  51.  ExitApp 
The images I used in this GUI are: and . These have to be saved in the same folder as the AHK script.

It took me a while to get the tooltip to show until I realised you have to specify the tooltip text BEFORE the gui,show command.

The above example is used in a search form where "SearchButton" is the name of the variable (picture) to change. Note that I am using the method of hiding the input button and putting an image over it.

The code above is only really a solution to if you have one image that you are applying this mouseover effect to. With a bit more time, you could tidy up the code to do multiple images.

Note: I've updated the above code so that even if you have other objects in the GUI, hovering the mouse over other objects will no longer cause the search button to flicker.

More...?

How about having the cursor change to hand when you hover the mouse over the image:

/*
IDC_ARROW := 32512
IDC_IBEAM := 32513
IDC_WAIT := 32514
IDC_CROSS := 32515
IDC_UPARROW := 32516
IDC_SIZE := 32640
IDC_ICON := 32641
IDC_SIZENWSE := 32642
IDC_SIZENESW := 32643
IDC_SIZEWE := 32644
IDC_SIZENS := 32645
IDC_SIZEALL := 32646
IDC_NO := 32648
IDC_HAND := 32649
IDC_APPSTARTING := 32650
IDC_HELP := 32651
*/

WM_MOUSEMOVE()
{
    static CurrControl, PrevControl, _TT  ; _TT is kept blank for use by the ToolTip command below.
    CurrControl := A_GuiControl

    SearchButton_Over:=A_ScriptDir "\images\program\icons\search_globe_over.png"
    SearchButton_Out:=A_ScriptDir "\images\program\icons\search_globe.png"

    If (CurrControl <> PrevControl and not InStr(CurrControl, " "))
    {
        ToolTip  ; Turn off any previous tooltip.
        SetTimer, DisplayToolTip, 1000
        If (PrevControl="SearchButton")
	{
		GuiControl,, SearchButton, %SearchButton_Out%
		RestoreCursors()
	}

        PrevControl := CurrControl
        If (CurrControl="SearchButton")
	{
		GuiControl,, SearchButton, %SearchButton_Over%
		SetSystemCursor("IDC_HAND")
	}
    }
    return

    DisplayToolTip:
    SetTimer, DisplayToolTip, Off
    ToolTip % %CurrControl%_TT  ; The leading percent sign tell it to use an expression.
    SetTimer, RemoveToolTip, 3000
    return

    RemoveToolTip:
    SetTimer, RemoveToolTip, Off
    ToolTip
    return
}

SetSystemCursor( Cursor = "", cx = 0, cy = 0 )
{
   BlankCursor := 0, SystemCursor := 0, FileCursor := 0 ; init

   SystemCursors = 32512IDC_ARROW, 32513IDC_IBEAM, 32514IDC_WAIT, 32515IDC_CROSS, 32516IDC_UPARROW, 32640IDC_SIZE, 32641IDC_ICON, 32642IDC_SIZENWSE, 32643IDC_SIZENESW, 32644IDC_SIZEWE, 32645IDC_SIZENS, 32646IDC_SIZEALL, 32648IDC_NO, 32649IDC_HAND, 32650IDC_APPSTARTING, 32651IDC_HELP

   If Cursor = ; empty, so create blank cursor
   {
      VarSetCapacity( AndMask, 32*4, 0xFF ), VarSetCapacity( XorMask, 32*4, 0 )
      BlankCursor = 1 ; flag for later
   }
   Else If SubStr( Cursor,1,4 ) = "IDC_" ; load system cursor
   {
      Loop, Parse, SystemCursors, `,
      {
         CursorName := SubStr( A_Loopfield, 6, 15 ) ; get the cursor name, no trailing space with substr
         CursorID := SubStr( A_Loopfield, 1, 5 ) ; get the cursor id
         SystemCursor = 1
         If ( CursorName = Cursor )
         {
            CursorHandle := DllCall( "LoadCursor", Uint,0, Int,CursorID )
            Break
         }
      }
      If CursorHandle = ; invalid cursor name given
      {
         Msgbox,, SetCursor, Error: Invalid cursor name
         CursorHandle = Error
      }
   }
   Else If FileExist( Cursor )
   {
      SplitPath, Cursor,,, Ext ; auto-detect type
      If Ext = ico
         uType := 0x1
      Else If Ext in cur,ani
         uType := 0x2
      Else ; invalid file ext
      {
         Msgbox,, SetCursor, Error: Invalid file type
         CursorHandle = Error
      }
      FileCursor = 1
   }
   Else
   {
      Msgbox,, SetCursor, Error: Invalid file path or cursor name
      CursorHandle = Error ; raise for later
   }
   If CursorHandle != Error
   {
      Loop, Parse, SystemCursors, `,
      {
         If BlankCursor = 1
         {
            Type = BlankCursor
            %Type%%A_Index% := DllCall( "CreateCursor", Uint,0, Int,0, Int,0, Int,32, Int,32, Uint,&AndMask, Uint,&XorMask )
            CursorHandle := DllCall( "CopyImage", Uint,%Type%%A_Index%, Uint,0x2, Int,0, Int,0, Int,0 )
            DllCall( "SetSystemCursor", Uint,CursorHandle, Int,SubStr( A_Loopfield, 1, 5 ) )
         }
         Else If SystemCursor = 1
         {
            Type = SystemCursor
            CursorHandle := DllCall( "LoadCursor", Uint,0, Int,CursorID )
            %Type%%A_Index% := DllCall( "CopyImage", Uint,CursorHandle, Uint,0x2, Int,cx, Int,cy, Uint,0 )
            CursorHandle := DllCall( "CopyImage", Uint,%Type%%A_Index%, Uint,0x2, Int,0, Int,0, Int,0 )
            DllCall( "SetSystemCursor", Uint,CursorHandle, Int,SubStr( A_Loopfield, 1, 5 ) )
         }
         Else If FileCursor = 1
         {
            Type = FileCursor
            %Type%%A_Index% := DllCall( "LoadImageA", UInt,0, Str,Cursor, UInt,uType, Int,cx, Int,cy, UInt,0x10 )
            DllCall( "SetSystemCursor", Uint,%Type%%A_Index%, Int,SubStr( A_Loopfield, 1, 5 ) )
         }
      }
   }
}

RestoreCursors()
{
   SPI_SETCURSORS := 0x57
   DllCall( "SystemParametersInfo", UInt,SPI_SETCURSORS, UInt,0, UInt,0, UInt,0 )
}

In this code, the IDC stuff commented out at the beginning is for your reference. You need to include the setsystemcursor() and restoreCursors() functions somewhere in your script.


Update: 07 July 2011: For Jose Luis

The images I used in this GUI are: and . These have to be saved in the same folder as the AHK script. Well they don't have to, I've just put A_ScriptDir and then the files but for my own program, I put them in folders.
Here's the whole code to make a gui with 1 image mouseover:
;
; AutoHotkey Version: 1.x
; Language:       English
; Platform:       Win9x/NT
; Author:         A.N.Other 
;
; Script Function:
;	Template script (you can customize this template by editing "ShellNew\Template.ahk" in your Windows folder)
;

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.


    ; SET TOOLTIP TEXT
    SearchButton_TT:="Search"

    ; SHOW THE GUI
    Gui, Color, FFFFFF
	Gui, Font, s16, Verdana,
	Gui, Add, Button, x575 y40 w85 h85 +Default +gSearch +Hide, Search
	Gui, Add, Picture, x573 y40 w93 h96 vSearchButton gSearch, %A_ScriptDir%\search_globe.png
	Gui, Add, Edit, x45 y40 w520 r1 vSearchTextInput Limit70, Search...
	Gui, Show
    	OnMessage(0x200, "WM_MOUSEMOVE")

Return

    ; FUNCTION TO HANDLE BOTH TOOLTIP AND MOUSEOVER EVENT
WM_MOUSEMOVE()
{
    static CurrControl, PrevControl, _TT  ; _TT is kept blank for use by the ToolTip command below.
    CurrControl := A_GuiControl

    SearchButton_Over:=A_ScriptDir "\search_globe_over.png"
    SearchButton_Out:=A_ScriptDir "\search_globe.png"

    If (CurrControl <> PrevControl and not InStr(CurrControl, " "))
    {
        ToolTip  ; Turn off any previous tooltip.
        SetTimer, DisplayToolTip, 1000
        If (PrevControl="SearchButton")
	{
		GuiControl,, SearchButton, %SearchButton_Out%
		RestoreCursors()
	}

        PrevControl := CurrControl
        If (CurrControl="SearchButton")
	{
		GuiControl,, SearchButton, %SearchButton_Over%
		SetSystemCursor("IDC_HAND")
	}
    }
    return

    DisplayToolTip:
    SetTimer, DisplayToolTip, Off
    ToolTip % %CurrControl%_TT  ; The leading percent sign tell it to use an expression.
    SetTimer, RemoveToolTip, 3000
    return

    RemoveToolTip:
    SetTimer, RemoveToolTip, Off
    ToolTip
    return
}

; ==================================================================================
; DON'T EDIT THESE FUNCTIONS BELOW (I have no idea how they work only that they do)

SetCursor(pShape, pCtrl="") {
   return SetCursor_(pShape, pCtrl, 0, 0)
}

SetCursor_(wparam, lparam, msg, hwnd) {
   static WM_SETCURSOR := 0x20, WM_MOUSEMOVE := 0x200
   static APPSTARTING := 32650,HAND := 32649 ,ARROW := 32512,CROSS := 32515 ,IBEAM := 32513 ,NO := 32648 ,SIZE := 32640 ,SIZEALL := 32646 ,SIZENESW := 32643 ,SIZENS := 32645 ,SIZENWSE := 32642 ,SIZEWE := 32644 ,UPARROW := 32516 ,WAIT := 32514
   static SIZEWE_BIG := 32653, SIZEALL_BIG := 32654, SIZEN_BIG := 32655, SIZES_BIG := 32656, SIZEW_BIG := 32657, SIZEE_BIG := 32658, SIZENW_BIG := 32659, SIZENE_BIG := 32660, SIZESW_BIG := 32661, SIZESE_BIG := 32662
   static hover, curOld=32512, cursor, ctrls="`n", init

   if !init
      init := 1, OnMessage(WM_SETCURSOR, "SetCursor_"),  OnMessage(WM_MOUSEMOVE, "SetCursor_")

   if A_Gui =
   {
      if wparam is not Integer
            If InStr( wparam, ".cur" ) || InStr( wparam, ".ani" ) {   ;LoadCursorFromFile
                 IfNotExist, % WPARAM  ; verify existance
                    return
                 cursor := DllCall("LoadCursorFromFile", "Str", WPARAM)
            }
            Else cursor := DllCall("LoadCursor", "Uint", 0, "Int", %WPARAM%, "Uint")

      if lparam =
            curOld := cursor
      else  ctrls .= lparam "=" cursor "`n"
   }

   If (msg = WM_SETCURSOR)
      ifEqual, hover, 1,   return 1

   if (msg = WM_MOUSEMOVE)
   {
      MouseGetPos, ,,,c
      If j := InStr(ctrls, "`n" c "=")
      {
         hover := true,
         j += 2+StrLen(c)
         j := SubStr(ctrls, j, InStr(ctrls, "`n", 0, j)-j+1)
         DllCall("SetCursor", "uint",j)
      }
      else DllCall("SetCursor", "uint", curOld), hover := ""
   }

}

SetSystemCursor( Cursor = "", cx = 0, cy = 0 )
{
   BlankCursor := 0, SystemCursor := 0, FileCursor := 0 ; init

   SystemCursors = 32512IDC_ARROW,32513IDC_IBEAM,32514IDC_WAIT,32515IDC_CROSS,32516IDC_UPARROW,32640IDC_SIZE,32641IDC_ICON,32642IDC_SIZENWSE,32643IDC_SIZENESW,32644IDC_SIZEWE,32645IDC_SIZENS,32646IDC_SIZEALL,32648IDC_NO,32649IDC_HAND,32650IDC_APPSTARTING,32651IDC_HELP

   If Cursor = ; empty, so create blank cursor
   {
      VarSetCapacity( AndMask, 32*4, 0xFF ), VarSetCapacity( XorMask, 32*4, 0 )
      BlankCursor = 1 ; flag for later
   }
   Else If SubStr( Cursor,1,4 ) = "IDC_" ; load system cursor
   {
      Loop, Parse, SystemCursors, `,
      {
         CursorName := SubStr( A_Loopfield, 6, 15 ) ; get the cursor name, no trailing space with substr
         CursorID := SubStr( A_Loopfield, 1, 5 ) ; get the cursor id
         SystemCursor = 1
         If ( CursorName = Cursor )
         {
            CursorHandle := DllCall( "LoadCursor", Uint,0, Int,CursorID )
            Break
         }
      }
      If CursorHandle = ; invalid cursor name given
      {
         Msgbox,, SetCursor, Error: Invalid cursor name
         CursorHandle = Error
      }
   }
   Else If FileExist( Cursor )
   {
      SplitPath, Cursor,,, Ext ; auto-detect type
      If Ext = ico
         uType := 0x1
      Else If Ext in cur,ani
         uType := 0x2
      Else ; invalid file ext
      {
         Msgbox,, SetCursor, Error: Invalid file type
         CursorHandle = Error
      }
      FileCursor = 1
   }
   Else
   {
      Msgbox,, SetCursor, Error: Invalid file path or cursor name
      CursorHandle = Error ; raise for later
   }
   If CursorHandle != Error
   {
      Loop, Parse, SystemCursors, `,
      {
         If BlankCursor = 1
         {
            Type = BlankCursor
            %Type%%A_Index% := DllCall( "CreateCursor", Uint,0, Int,0, Int,0, Int,32, Int,32, Uint,&AndMask, Uint,&XorMask )
            CursorHandle := DllCall( "CopyImage", Uint,%Type%%A_Index%, Uint,0x2, Int,0, Int,0, Int,0 )
            DllCall( "SetSystemCursor", Uint,CursorHandle, Int,SubStr( A_Loopfield, 1, 5 ) )
         }
         Else If SystemCursor = 1
         {
            Type = SystemCursor
            CursorHandle := DllCall( "LoadCursor", Uint,0, Int,CursorID )
            %Type%%A_Index% := DllCall( "CopyImage", Uint,CursorHandle, Uint,0x2, Int,cx, Int,cy, Uint,0 )
            CursorHandle := DllCall( "CopyImage", Uint,%Type%%A_Index%, Uint,0x2, Int,0, Int,0, Int,0 )
            DllCall( "SetSystemCursor", Uint,CursorHandle, Int,SubStr( A_Loopfield, 1, 5 ) )
         }
         Else If FileCursor = 1
         {
            Type = FileCursor
            %Type%%A_Index% := DllCall( "LoadImageA", UInt,0, Str,Cursor, UInt,uType, Int,cx, Int,cy, UInt,0x10 )
            DllCall( "SetSystemCursor", Uint,%Type%%A_Index%, Int,SubStr( A_Loopfield, 1, 5 ) )
         }
      }
   }
}

RestoreCursors()
{
   SPI_SETCURSORS := 0x57
   DllCall( "SystemParametersInfo", UInt,SPI_SETCURSORS, UInt,0, UInt,0, UInt,0 )
}

; ==================================================================================
; GUI FUNCTIONS

Search:
	MsgBox, Searching...
Return

GuiClose:
Exitapp

The images I used in the search GUI above are: and . These have to be saved in the same folder as the AHK script. Well they don't have to, I've just put A_ScriptDir and then the files but for my own program, I put them in folders.

These functions are documented in the autohotkey forums at http://www.autohotkey.com/forum/topic35600-15.html

Enjoy!

Category: AutoHotkey :: Article: 232

Credit where Credit is Due:


Feel free to copy, redistribute and share this information. All that we ask is that you attribute credit and possibly even a link back to this website as it really helps in our search engine rankings.

Disclaimer: The information on this website is provided without warranty and any content is merely the opinion of the author. Please try to test in development environments prior to adapting them to your production environments. The articles are written in good faith and, at the time of print, are working examples used in a commercial setting.

Thank you for visiting and, as always, we hope this website was of some use to you!

Kind Regards,

Joel Lipman
www.joellipman.com

Related Articles

Joes Revolver Map

Accreditation

Badge - Certified Zoho Creator Associate
Badge - Certified Zoho Creator Associate

Donate & Support

If you like my content, and would like to support this sharing site, feel free to donate using a method below:

Paypal:
Donate to Joel Lipman via PayPal

Bitcoin:
Donate to Joel Lipman with Bitcoin - Valid till 8 May 2022 3QnhmaBX7LQSRsC9hh6Je9rGQKEGNQNfPb
© 2021 Joel Lipman .com. All Rights Reserved.