Date: | June 26, 2006 / year-entry #212 |
Tags: | code |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20060626-11/?p=30743 |
Comments: | 17 |
Summary: | Today we'll look at how to implement in-place tooltips. These are tooltips that appear when the user hovers the mouse over a string that cannot be displayed in its entirety. The tooltip overlays the partially-displayed text and provides the remainder of the text that had been truncated. The keys to this technique are the TTN_SHOW... |
Today we'll look at how to implement in-place tooltips.
These are tooltips that appear when the user hovers the mouse
over a string that cannot be displayed in its entirety.
The tooltip overlays the partially-displayed text and provides
the remainder of the text that had been truncated.
The keys to this technique are the
Start with our scratch program and add the following: HFONT g_hfTT; HWND g_hwndTT; RECT g_rcText; LPCTSTR g_pszText = TEXT("Lorem ipsum dolor sit amet."); const int c_xText = 50; const int c_yText = 50; BOOL OnCreate(HWND hwnd, LPCREATESTRUCT lpcs) { g_hwndTT = CreateWindowEx(WS_EX_TRANSPARENT, TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0, hwnd, NULL, g_hinst, NULL); if (!g_hwndTT) return FALSE; g_hfTT = GetStockFont(ANSI_VAR_FONT); SetWindowFont(g_hwndTT, g_hfTT, FALSE); HDC hdc = GetDC(hwnd); HFONT hfPrev = SelectFont(hdc, g_hfTT); SIZE siz; GetTextExtentPoint(hdc, g_pszText, lstrlen(g_pszText), &siz); SetRect(&g_rcText, c_xText, c_yText, c_xText + siz.cx, c_yText + siz.cy); SelectFont(hdc, hfPrev); ReleaseDC(hwnd, hdc); TOOLINFO ti = { sizeof(ti) }; ti.uFlags = TTF_TRANSPARENT | TTF_SUBCLASS; ti.hwnd = hwnd; ti.uId = 0; ti.lpszText = const_cast<LPTSTR>(g_pszText); ti.rect = g_rcText; SendMessage(g_hwndTT, TTM_ADDTOOL, 0, (LPARAM)&ti); return TRUE; } void PaintContent(HWND hwnd, PAINTSTRUCT *pps) { HFONT hfPrev = SelectFont(pps->hdc, g_hfTT); TextOut(pps->hdc, g_rcText.left, g_rcText.top, g_pszText, lstrlen(g_pszText)); SelectFont(pps->hdc, hfPrev); }
After declaring a few variables, we dig into our
computations at window creation.
We create the tooltip window, passing ourselves as the
owner window.
(Passing ourselves as the owner window is important in order
to get proper Z-order behavior.
I refer the reader to the fifth of my "Five Things Every
Win32 Developer Should Know" topics for further details.)
We then obtain our font and set it into the tooltip control
so that the tooltip renders in the same font we do.
(I'll take up more complex font manipulation in a future entry.)
We then measure our text in the target font and set
the Painting the content is a simple matter of selecting the font and drawing the text. Run this program and hover over the text. The tooltip appears, but it's in the wrong place. Aside from that, though, things are working as expected. The tooltip has the correct font, it fires only when the mouse is over the text itself, and it dismisses when the mouse leaves the text. Let's position the tooltip: LRESULT OnTooltipShow(HWND hwnd, NMHDR *pnm) { RECT rc = g_rcText; MapWindowRect(hwnd, NULL, &rc); SendMessage(pnm->hwndFrom, TTM_ADJUSTRECT, TRUE, (LPARAM)&rc); SetWindowPos(pnm->hwndFrom, 0, rc.left, rc.top, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER); return TRUE; // suppress default positioning } LRESULT OnNotify(HWND hwnd, int idFrom, NMHDR *pnm) { if (pnm->hwndFrom == g_hwndTT) { switch (pnm->code) { case TTN_SHOW: return OnTooltipShow(hwnd, pnm); } } return 0; } // Add to WndProc HANDLE_MSG(hwnd, WM_NOTIFY, OnNotify);
The When you run this program, you will find one more problem: Tooltip animations are still taking place, which is particularly distracting if the animation is a slide animation. This is easy to fix: Tweak the way we create the tooltip control. g_hwndTT = CreateWindowEx(WS_EX_TRANSPARENT, TOOLTIPS_CLASS, NULL, TTS_NOPREFIX | TTS_NOANIMATE, 0, 0, 0, 0, hwnd, NULL, g_hinst, NULL);
The So there you have it—the basics of in-place tooltips. Of course, there are many details you may wish to deal with, such as showing the tooltip only if the string is clipped. But those issues are independent of in-place tooltips, so I won't go into them here. We'll look at selected aspects of tooltips in future installments. |
Comments (17)
Comments are closed. |
The tooltip doesn’t have a black border on Windows 2000. Any clue ?
Worst on Vista, the tooltip has a black border once out of four…
Why not in C++ style? Did you forget about your new scratch program? :)
As a note regarding GetTextExtentPoint at MSDN says:
"This function is provided only for compatibility with 16-bit versions of Windows. Applications should call the GetTextExtentPoint32 function, which provides more accurate results."
So why not use the "proper" one? [besides not needing the increased accurancy]
Do you suggest to still be compatible with 16-bit Windows or did you use it just for simplicity’s sake? Just curious of your point of view.
Anyway thanks for the tip, Raymond!
So, how did they get it so wrong in Microsoft Document Explorer for the tree view in the left pane, bundled with VS 2005?
If the pane is narrow (or the text is wide) the entire pane flickers when the tooltip is displayed.
Or are you still building with VC 6 Raymond, so haven’t had the japanese style flashing animations?
Raymond,
I didn’t expect you to know. It was more of a rhetorical discussion point; just wondered if you had noticed, and had perhaps applied your "psychic powers" of debugging as you’ve mentioned before.
Sorry if it came over the wrong way.
Your timing is spookily weird though sometimes. Just the other day I built a DDE server for a client, and what pops up, but an article on DDE from you.
Raymond,
This kind of posts are worth gold. Straight to the point, solving real-world programming problems.
The thing I just can’t understand is how many hours you can pack in 24! Keep up with the great blog.
Changing the font is the most common customization.
I love how Norman uses your blog as his personal bitch-at-Microsoft forum
I’ve implemented something very similar to this some time ago. I
respond to TTN_SHOW just like you do, but instead of using
SendMessage(…, TTM_ADJUSTRECT, …), I call SetWindowPos() without
SWP_NOSIZE and with the desired size. It works fine, but is it wrong?
"therefore I made a worthless suggestion."
Maybe it’s not that your suggestions are worthless, but instead it’s just that you complain so much that everything you say starts to become this annoying buzz that people try to ignore. Perhaps you can try to be constructive once in your life and you’ll actually get people who want work with you instead of wanting nothing to do with you.
Nobody likes a chronic complainer.
Sorry, I’ve never heard of TTM_ADJUSTRECT and I should have read the documentation before bothering you with this… You are right, I am “hard-coding” a number: it’s an owner-drawn list with an owner-drawn tooltip, so I know exactly how big the tooltip should be. Before reading about TTM_ADJUSTRECT on MSDN, I thought it was being used only to set the tooltip’s size.
Wednesday, June 28, 2006 1:43 PM by J
> Perhaps you can try to be constructive once
> in your life
Well obviously I wasn’t constructive with this one:
>> If your subsequent articles include an
>> example for "if and only if" instead of just
>> "only if", please consider sending it to
>> your colleagues who work on Outlook Express.
so I think I’m genetically incapable of it, sorry. The only constructive things I get to do are code.
> Nobody likes a chronic complainer.
Right. Even I don’t. I wish that the number of causes for complaint would go down.
PingBack from http://blogs.msdn.com/oldnewthing/archive/2006/07/13/664448.aspx
PingBack from http://cardboxeverywhere.wordpress.com/2007/12/11/programming-note-tooltips-again/