Sign in to follow this  
Followers 0
doudou

How To: add a dynamic ToolTip to a ListView header (or anything else)

3 posts in this topic

It is easy to set tooltips for standard AutoIt GUI controls by calling GUICtrlSetTip(). But what if you want to reflect some dynamically changing data in that tooltip or you have some custom control what you only know about is a HWND (like a ListView header)? In this case Common Controls API and the notification message TTN_GETDISPINFO is the way to go.

Almost everything you need is in the GuiToolTip.au3 (Standard UDF). However _GUIToolTip_AddTool() of all functions there has small functionality flaw (s. AutoIt Track), so we cannot add a tool to the tooltip that would send us TTN_GETDISPINFO. Therefore I created a modified version _GUIToolTip_AddToolMod(), using that you can add a dynamic tooltip to any GUI control.

The following example shows the basic usage with a ListView header and 2 labels (just as placeholders for whatever you like), also it demonstrates, what the $iParam argument in _GUIToolTip_AddTool()/_GUIToolTip_AddToolMod() is good for.

#include <Constants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>
#include <WinAPI.au3>
#include <GUIListView.au3>
#include <GUIHeader.au3>
#include <GUIToolTip.au3>

Global Const $LPSTR_TEXTCALLBACK = -1

#Region GUI
Global $frmMain = GUICreate("TTN_GETDISPINFO", 530, 396, -1, -1, BitOR($WS_MINIMIZEBOX,$WS_SIZEBOX,$WS_THICKFRAME,$WS_SYSMENU,$WS_CAPTION,$WS_POPUP,$WS_POPUPWINDOW,$WS_GROUP,$WS_VISIBLE,$WS_BORDER,$WS_CLIPSIBLINGS), BitOR($WS_EX_ACCEPTFILES,$WS_EX_WINDOWEDGE))
Global $lblRed = GUICtrlCreateLabel("Red (move mouse over here)", 1, 1, 274, 205, $SS_CENTER)
GUICtrlSetBkColor($lblRed, 0xff0000)
Global $lblGreen = GUICtrlCreateLabel("Green (move mouse over here)", 274, 1, 274, 205, $SS_CENTER)
GUICtrlSetBkColor($lblGreen, 0x00ff00)
Global $lvwTest = GUICtrlCreateListView("Column 0|Column 1|Column 2", 1, 206, 528, 190, BitOR($LVS_REPORT,$LVS_SINGLESEL,$LVS_SHOWSELALWAYS,$WS_TABSTOP,$WS_VISIBLE,$WS_CHILD,$WS_CLIPSIBLINGS), BitOR($WS_EX_CLIENTEDGE,$LVS_EX_FULLROWSELECT,$LVS_EX_FLATSB,$LVS_EX_INFOTIP))

For $i = 0 To 9
    GUICtrlCreateListViewItem("Item " & $i & "|Whatever|Whatever", $lvwTest)
Next
Global $lvwTest_hHeader = _GUICtrlListView_GetHeader($lvwTest)
Global $hToolTip = _GUIToolTip_Create($frmMain)
#EndRegion

Main()

Func Main()
    GUIRegisterMsg($WM_NOTIFY, "On_WM_NOTIFY")
    _GUIToolTip_AddToolMod($hToolTip, $frmMain, $LPSTR_TEXTCALLBACK, _GUICtrl_GetHandle($lblRed), 0, 0, 0, 0, BitOr(1, 8), _GUICtrl_GetHandle($lblRed))
    _GUIToolTip_AddToolMod($hToolTip, $frmMain, $LPSTR_TEXTCALLBACK, _GUICtrl_GetHandle($lblGreen), 0, 0, 0, 0, BitOr(1, 8), _GUICtrl_GetHandle($lblGreen))
    _GUIToolTip_AddToolMod($hToolTip, $frmMain, $LPSTR_TEXTCALLBACK, $lvwTest_hHeader, 0, 0, 0, 0, BitOr(1, 8), $lvwTest_hHeader)
    While CheckGUIMsg()
        ;
    WEnd
EndFunc

Func CheckGUIMsg()
    Local $msg = GUIGetMsg()
    Select
        Case $msg = $GUI_EVENT_CLOSE
            Return False
    EndSelect
    Return True
EndFunc

Func On_WM_NOTIFY($hWnd, $msg, $wParam, $lParam)
    Local $nmhdr = DllStructCreate($tagNMHDR, $lParam)
    Local $hWndFrom = HWnd(DllStructGetData($nmhdr, "hWndFrom"))
    Local $iCode = DllStructGetData($nmhdr, "Code")
    
    If _GUICtrl_GetHandle($hToolTip) = $hWndFrom Then
        Switch $iCode
            Case $TTN_GETDISPINFO, $TTN_GETDISPINFOW
                Local $nmttdi = DllStructCreate($tagNMTTDISPINFO, $lParam)
                Local $hTool = HWnd(DllStructGetData($nmttdi, "Param"))
                
                Local $pos = _GUICtrl_GetMessagePos($hTool)
                
                Switch $hTool
                    Case $lvwTest_hHeader
                        Local $ht = _GUICtrlHeader_HitTest($hTool, $pos[0], $pos[1])
                        If -1 < $ht[0] Then
                            DllStructSetData($nmttdi, "aText", StringStripWS(_GUICtrlHeader_GetItemText($hTool, $ht[0]), 1 + 2))
                        EndIf
                    Case _GUICtrl_GetHandle($lblRed)
                        DllStructSetData($nmttdi, "aText", "Red (at x=" & $pos[0] & ", y=" & $pos[1] & ")")
                    Case _GUICtrl_GetHandle($lblGreen)
                        DllStructSetData($nmttdi, "aText", "Green (at x=" & $pos[0] & ", y=" & $pos[1] & ")")
                EndSwitch
        EndSwitch
    EndIf
    
    Return $GUI_RUNDEFMSG
EndFunc

Func _GUIToolTip_AddToolMod($hTool, $hWnd, $sText, $iID = 0, $iLeft = 0, $iTop = 0, $iRight = 0, $iBottom = 0, $iFlags = 8, $iParam = 0)
    Local $tToolInfo = DllStructCreate($tagTOOLINFO)
    Local $pToolInfo = DllStructGetPtr($tToolInfo)
    Local $iToolInfo = DllStructGetSize($tToolInfo)
    DllStructSetData($tToolInfo, "Size", $iToolInfo)
    DllStructSetData($tToolInfo, "Flags", _GUIToolTip_BitsToTTF($iFlags))
    DllStructSetData($tToolInfo, "hWnd", $hWnd)
    DllStructSetData($tToolInfo, "ID", $iID)
    DllStructSetData($tToolInfo, "Left", $iLeft)
    DllStructSetData($tToolInfo, "Top", $iTop)
    DllStructSetData($tToolInfo, "Right", $iRight)
    DllStructSetData($tToolInfo, "Bottom", $iBottom)
    DllStructSetData($tToolInfo, "Param", $iParam)
    
    Local $iRet = 0
    If IsString($sText) Then
        Local $iBuffer = StringLen($sText) + 1
        Local $tBuffer = DllStructCreate("wchar Text[" & $iBuffer & "]")
        $iBuffer *= 2
        Local $pBuffer = DllStructGetPtr($tBuffer)
        DllStructSetData($tBuffer, "Text", $sText)
        DllStructSetData($tToolInfo, "Text", $pBuffer)
        $iRet = _SendMessage($hTool, $TTM_ADDTOOLW, 0, $pToolInfo, 0, "wparam", "ptr")
    Else
        DllStructSetData($tToolInfo, "Text", $sText)
        $iRet = _SendMessage($hTool, $TTM_ADDTOOLW, 0, $pToolInfo, 0, "wparam", "ptr")
    EndIf
    Return $iRet <> 0
EndFunc

Func _GUICtrl_GetHandle($control)
    If IsHWnd($control) Then Return $control
    Return GUICtrlGetHandle($control)
EndFunc

Func _GUICtrl_GetMessagePos($control)
    Local $p = DllCall("user32.dll", "DWORD", "GetMessagePos")
    Local $pt = DllStructCreate($tagPOINT)
    DllStructSetData($pt, "X", _WinAPI_LoWord($p[0]))
    DllStructSetData($pt, "Y", _WinAPI_HiWord($p[0]))
    _WinAPI_ScreenToClient(_GUICtrl_GetHandle($control), $pt)
    Local $result[2] = [DllStructGetData($pt, "X"), DllStructGetData($pt, "Y")]
    Return $result
EndFunc

Have fun with it.


UDFS & Apps:


DDEML.au3 - DDE Client + Server[*]
Localization.au3- localize your scripts[*]
TLI.au3 - type information on COM objects (TLBINF emulation)[*]
TLBAutoEnum.au3 - auto-import of COM constants (enums)[*]
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector

- OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCE 

Share this post


Link to post
Share on other sites



Thanks for the post.

Can you modify the same example to display ToolTip for ListView Subitems.

Share this post


Link to post
Share on other sites

Great functionality which I will definitely use. Thanks for sharing.

Small gripe though - the tooltip does not change when you move mouse across

from one header to the next, only changes when you move out of header 'zone'

and then back onto to the next header.

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
Sign in to follow this  
Followers 0