Just finished a li'l testbed, pretty much in one sitting, that gets me up and running on tooltips. Even though it seemed daunting at first, and really complicated, it turns out to be not too hard after all.
So I wanted to share my "recipe" with any of you who might be wanting to try this. I got
most of my information from MSDN, but it turns out that in addition to there being gaps in their explanations, there's also some erroneous stuff there. The attached .zip has a little program that shows how to implement tooltips.
Here's my recipe:
1.. Prepare the Common Controls DLL by calling InitCommonControlsEx(), specifying
ICC_BAR_CLASSES (at least; you can add other classes of controls as well.) (This is something that's not mentioned
at all in the MSDN info, presumably because this is already done for the programmer using Visual C or .net or whatever.)
2. Create the toolbar window with the
TBSTYLE_LIST and
TBSTYLE_TOOLTIPS styles.
3. Create the toolbar as usual, loading bitmap(s) (if any), creating buttons, etc.
4. Set the
TBSTYLE_EX_MIXEDBUTTONS "extended style" (by sending a
SETEXTENDEDSTYLE message to the control).
5. Handle the
TTN_NEEDTEXT (alias
TTN_GETDISPINFO, same thing) notification. This will come as a code in a
WM_NOTIFY message. Look at the control ID in the
NMHDR header of the message; if it matches your toolbar button, then all you need to do is to specify the text for the tooltip. (This can be done either by copying the text into the
NMTTDISPINFO structure itself, or by giving it the address of a string in your application (or as the handle to a string resource). You should also set the
TTF_DI_SETITEM flag (in the "uFlags" member) so that Windows will save the text and not bother you again.
Here's the (apparently) erroneous MSDN information:
- They tell us to put pointers to tooltip text in the "iString" members of the TBBUTTON structures, and to send the TB_SETMAXTEXTROWS message to set the max. # of rows to zero. Both of these things appear to be completely unnecessary (at least my tooltips work fine without them). It seemed really silly to put pointers to the strings in these structures when creating the tooltips, and setting the text in the notification handler.
- It is also not necessary to respond to the TBN_GETINFOTIP notification (only TTN_NEEDTEXT/TTN_GETDISPINFO needs to be handled).
Both of these mistaken instructions come from an otherwise fairly comprehensive and helpful page (http://msdn.microsoft.com/en-us/library/hh298386%28v=VS.85%29.aspx) on tooltips.
I also came up with a really simple way to initialize all those toolbar strings. If you have a lot of toolbar buttons, it can be a real pain in the ass to initialize all of them in the message handler. The dumb way would be something like
MOV EDX, lParam ;--> NMTTDISPINFO struct.
MOV EAX, [EDX + NMHDR.idFrom] ;Could be the ID of one of our controls.
CMP EAX, $controlID1
JE do_control1
CMP EAX, $controlID2
JE do_control2
... etc. ...
do_control1:
LEA EAX, TextForToolbarButton1
MOV [EDX + NMTTDISPINFO.lpszText], EAX ;Ptr. to tooltip text.
MOV [EDX + NMTTDISPINFO.uFlags], TTF_DI_SETITEM ;Don't bother me again!
which amounts to a whole lot of IF-ELSEing for all those buttons!
Use indexing instead:
;===== Toolbar button IDs: =====
$TBbutton1 EQU 1500
$TBbutton2 EQU 1501
$TBbutton3 EQU 1502
$TBbutton4 EQU 1503
$TBbutton5 EQU 1504
$TBbutton6 EQU 1505
$TBbutton7 EQU 1506
$TBbutton8 EQU 1507
ToolTipTextPtrs DD BTN1text, BTN2text, BTN3text, BTN4text
DD BTN5text, BTN6text, BTN7text, BTN8text
BTN1text DB "whole note", 0
BTN2text DB "half note", 0
BTN3text DB "quarter note", 0
BTN4text DB "8th note", 0
BTN5text DB "whole rest", 0
BTN6text DB "half rest", 0
BTN7text DB "quarter rest", 0
BTN8text DB "8th rest", 0
(message handler for WM_NOTIFY:)
MOV EDX, lParam ;--> NMTTDISPINFO struct.
CMP [EDX + NMHDR.code], TTN_NEEDTEXT ;aka TTN_GETDISPINFO
JNE dodefault
MOV EAX, [EDX + NMHDR.idFrom] ;Could be the ID of one of our controls.
CMP EAX, $TBbutton1
JB dodefault
CMP EAX, $TBbutton8
JA dodefault
; At this point, we have a TTN_NEEDTEXT message for one of our buttons:
SUB EAX, $TBbutton1 ;Get offset from 1st button ID:
SHL EAX, 2 ;convert to DWORD offset
MOV EAX, [EAX + OFFSET ToolTipTextPtrs]
MOV [EDX + NMTTDISPINFO.lpszText], EAX ;Ptr. to tooltip text.
MOV [EDX + NMTTDISPINFO.uFlags], TTF_DI_SETITEM ;Don't bother me again!
RET ;No particular return value needed.
This works because all the toolbar button IDs are in a contiguous block, so I can use the ID passed in as an index into the list of pointers. Easy peasy!
I have to revise my "recipe". Tooltips are even easier than I described.
If you set the styles as I explained, and set the iString member of the TBBUTTON structure to point to your tooltip text strings, you don't even need to mess around at all with any notifications. (I guess you might want to use the notifications if you need to implement dynamic tooltip strings where the tooltips change during program execution.)
The really lazy boyz use this...
Quote CASE WM_CREATE
...
ToolTips TTS_BALLOON
ToolTips hEdit, "Type something useful"
ToolTips hButton1, "Click on this button"