Click here to Skip to main content
15,880,608 members
Articles / Desktop Programming / MFC

Neat Tooltip for ComboBox

Rate me:
Please Sign up or sign in to vote.
4.29/5 (18 votes)
30 Jul 2012BSD5 min read 239.9K   5.4K   66   50
Details of how to make a tool-tip for combobox
In this article, you will find out about the details of making a tool-tip for a combobox. The enhanced class CTTCombobox is derived from the MFC ComboBox class.

Image 1

Image 2

Image 3

Image 4

Introduction

I have always been perplexed by the question "which's the tool-tip associated with ComboBox?". On the internet, I searched a lot for samples about this, but the samples looked so complex, and some of the samples wrapped the ComboBox using separate controls CListbox, CEdit, CButton, requiring to generate many extra classes for the ComboBox, resulting in lots of work to maintain the ComboBox. A couple of samples used hooks for window subclassing so that all the messages go to a new WindowProc (window procedure) before going to the ComboBox, ummm..., that's very useful. But that is still not enough. Thus, based on these samples, I wrapped an enhanced class CTTCombobox. According to the expectation, they use the new WindowProc to hold the ListBox's messages and to do the tool-tip things. By the way, for the enhanced class CTTCombobox, the source files contain only TTCombobox.h and TTCombobox.cpp, which is very easy to embed into your VC++ project.

Noteworthy

The class CTTComboBox isn't wrapped using separate controls CListbox, CEdit, CButton.

To Use

  1. The class CTTComboBox is derived from an MFC class CCombobox. You can immediately use the class CTTComboBox as well as derive new classes from it.
  2. By default, tool-tip is allowed for the ComboBox (instance of the class CTTComboBox); to enable/disable the tool-tip, you need to perform the SetToolTipp function before creating or subclassing the ComboBox; for details, see the attached demo project.
  3. Use the SetToolTipDelay function to set up the appropriate delay time for showing the tool-tip window.

Implementation

As mentioned above, by default, tool-tip is allowed, means m_isEnableTool is TRUE; see the code sample given below:

C++
void  CTTComboBox::PreSubclassWindow() 
{
 CComboBox::PreSubclassWindow();

 // If the combo-box isn't dynamically 
 // subclassed that should get rid of 
 // the codes as follows and the codes should be 
 // placed in the OnCreate function.
 if (m_isEnableTool == TRUE)
 {
  CreateTooltipWnd();
  InstallHookForListboxAndEditbox();
 }
}

We have called the CreateTooltipWnd function to create a tool-tip window. (Note: All the ComboBoxes with the same class CTTComboBox share a tool-tip window.) Now, we have to install a hook for subclassing the list-box and the edit-box portion of the ComboBox, see the InstallHookForListboxAndEditbox function given below:

C++
void CTTComboBox::InstallHookForListboxAndEditbox()
{
 // Get the list-box/edit-box within the combobox 
 // and set up hooking with it.
 // Note: this only for Win98 or WinNT5.0 or later, 
 // However you must defined WINVER >= 0x0500 
 // within the project
 COMBOBOXINFO cbi;
 ZeroMemory(&cbi, sizeof(COMBOBOXINFO));
 cbi.cbSize = sizeof(COMBOBOXINFO);
 ::GetComboBoxInfo(m_hWnd, &cbi);
 m_rcButton = cbi.rcButton;

 if (cbi.hwndList)
 {
  m_hWndList = cbi.hwndList;

  // Set up hooking for the list-box within the combobox
  // Note: Refer to MSDN, In Windows NT/2000, You cannot 
  // change this attribute(GWL_WNDPROC) 
  // if the window(i.e, list-box) does not belong to the 
  // same process as the calling thread.
  WNDPROC oldListWndProc = (WNDPROC)::SetWindowLong(cbi.hwndList, 
                         GWL_WNDPROC, (DWORD)HookListboxWndProc);
  // Add the old hook(i.e, hook associated 
  // with window) to the map
  m_mapWndProc.SetAt(cbi.hwndList, oldListWndProc);
 }
 
 if (cbi.hwndItem)
 {
  m_hWndEdit = cbi.hwndItem;

  // Set up hooking for the edit-box within the combobox
  // Note: Refer to MSDN, In Windows NT/2000, You cannot 
  // change this attribute(GWL_WNDPROC) 
  // if the window(i.e, edit-box) does not belong to the 
  // same process as the calling thread.
  WNDPROC oldEditWndProc = (WNDPROC)::SetWindowLong(cbi.hwndItem, 
                         GWL_WNDPROC, (DWORD)HookEditboxWndProc);
  // Add the old hook(i.e, hook associated 
  // with window) to the map
  m_mapWndProc.SetAt(cbi.hwndItem, oldEditWndProc);
 }
}

The GetComboBoxInfo function gets the handles to the list-box and the edit-box, then the SetWindowLong function creates the list-box and the edit-box subclasses, causing the system to call the new window procedure instead of the previous one, a trick, that's all previous (old) window procedures have been added to the map. Later, we will reuse the old window procedure in the new window procedure, such as the window procedure - HookListboxWndProc with the list-box:

C++
LRESULT CALLBACK CTTComboBox::HookListboxWndProc(HWND hWnd, 
        UINT message, WPARAM wParam, LPARAM lParam)
{
 CListBox* pList = (CListBox*)CWnd::FromHandle(hWnd);

 if (message == WM_MOUSEMOVE)
 {
  WORD xPos, yPos;
  xPos = LOWORD(lParam);
  yPos = HIWORD(lParam);
  CPoint point(xPos, yPos); 
  CRect rcClient;
  ::GetClientRect(hWnd, &rcClient);
  if (rcClient.PtInRect(point))
  {
   // Handle mouse move event that may 
   // show a tool-tip window...
   CTTComboBox::HandleListboxMouseMove(pList, 
                                 wParam, point);
  }

  if (!m_isEnter)
  {
   // Tracking the mouse event which 
   // are hovering and leaving.
   OnTrackMouseEvent(hWnd, TME_HOVER|TME_LEAVE);
   m_isEnter = TRUE;
  }
 }
 else if (message == WM_MOUSELEAVE)
 {
  // When the mouse cursor has been 
  // left current window, 
  // the original select of the list-box 
  // to reset LB_ERR.
  m_OriginalSel = LB_ERR;
  m_isEnter = FALSE;
 }
 else if (message == WM_CAPTURECHANGED)
 { // To omit the mouse capture changed...
  return 1;
 }

 // Get previous window procedure
 WNDPROC oldListWndProc;
 m_mapWndProc.Lookup(hWnd, oldListWndProc);
 // Call previous window procedure
 return ::CallWindowProc(oldListWndProc, 
            hWnd, message, wParam, lParam);
}

At the end of the function, we reuse the old window procedure by calling the CallWindowProc function from the map like a chain of window procedures. Some of the messages have been reprocessed for the list-box. While processing the WM_MOUSEMOVE, the HandleListboxMouseMove function determines whether or not the tool-tip window has to be shown/hidden, and the OnTrackMouseEvent function tracks the mouse event messages WM_MOUSEHOVER or WM_MOUSELEAVE, that reset the original selection of the list-box when firing up WM_MOUSELEAVE. Waiting..., the WM_MOUSELEAVE message takes a continuous place, but the mouse cursor will still be above the list-box, actually, the mouse cursor will be above the tool-tip window when the tool-tip window shows up, think over? So we must capture the list-box to prevent this, to release the mouse capture only when the tool-tip has been hidden.

The ComboBox with owner DropList or DropDown style has a little trouble: when the mouse capture is released, the list-box becomes invisible. So, I have to hold the WM_CAPTURECHANGED and ignore the message...

Usage

You are allowed to use it for free and further modify it according to your needs.

Updates

There are two extra features for the class CTTCombobox, it now supports these features:

Thanks d3m0n, for finding out some bugs in the control. I have fixed all the bugs as follows:

The updated source and demo projects now support the X64 platform and Unicode version compilation for all platforms (Win32 and X64), and a few minor issues have been fixed. The demo project gives two project solutions respectively for VC6.0 and VS2005. Naturally, you can upgrade the solution with VS2008/VS2010.

There is a new function - SetTipText(int nIndex, LPCTSTR pszTipText). The function gives a customized method to setup tip text for a specified item. Note: This will force the display of the tip text, and if the customized tip text is no longer needed for that item, you're responsible to call the function again and pass pszTipText=NULL.

  • 8th June, 2005
    • Hover over the ComboBox and the tool tip appears. Then while the tool tip is still visible, click the arrow to expand the ComboBox. The dropdown list appears and then disappears immediately.
    • While the tool tip is visible, nothing can receive the focus, e.g., try clicking the Cancel button while the tool tip is visible.
    • The size of the tool tip is sometimes too big, e.g., hover over the ListBox, wait for the tool tip to appear and disappear, now move the mouse out of the ListBox. Now move it into the edit box. The size of the tool tip is really too big.
  • 27th September, 2006
    • Allows that you align the listbox by the three modes CTTCombobox::alignLeft, CTTCombobox::alignRight, CTTCombobox::alignMiddle, using the function SetAlignStyle to do this thing.
    • To disable or enable any items in a combobox, you only simply perform the function SetDisabledItem. Note: That's not effective when the combobox does not have the CBS_OWNERDRAWFIXED style, so I suggest you should set the style. There are three methods to gain the style CBS_OWNERDRAWFIXED.
      1. You directly check the style for the combobox in the resource.
      2. If the combobox was created dynamically, then you should do the thing in OnCreate(LPCREATESTRUCT lpCreateStruct). Usually, you write the code lpCreateStruct->style |= CBS_OWNERDRAWFIXED | CBS_HASSTRINGS; as the first line in the function OnCreate(LPCREATESTRUCT lpCreateStruct).
      3. If the combobox was subclassed dynamically, then you add the code: ModifyStyle(0, CBS_OWNERDRAWFIXED | CBS_HASSTRINGS); as the first line in PreSubclassWindow().
  • 21st July, 2011: Update
  • 19th November, 2011: Update

License

This article, along with any associated source code and files, is licensed under The BSD License


Written By
Software Developer (Senior) www.likefreelancer.com
China China
I was borned at Jianghan district, Qianjiang Hubei province of China, and always pursuiting his dream in Beijing.

Last century 1996, I got a learning machine called Subor(1.8MHZ CPU, 2k memory) that it can be connected to TV looked like computer emulater, the machine is really good for learning G-Basic, and Wubi inputs, after soon, A real PC was presented to me, the core was 586 pentium MMX, really graceful! in that mean-time, I practiced Javascript language and dynamic HTML on that PC, of course, including many famouse classic games. also, I have further self-studied professional electronic courses via Wuhan University.

A great starting point was in 2001, I went to a software firm and did deepth experience in real software development, learned C/C++ and ASP(VBscript).

In 2005, I moved to another creative firm, major responsibility is to develop windows GUI based on MFC framework, and early touched Mac PowerPC and Macbook for migrating soft. I'm still there and developing a great social web application.

In 2007, I have married with my wife and had a very cute daughter she's close to 3 old now. At all available time, I has been activating on freelancer.com and doing lots of amazing jobs.

Comments and Discussions

 
QuestionIs it possible to port this over to CCheckListBox control? Pin
Andrew Truckle16-Aug-23 10:39
professionalAndrew Truckle16-Aug-23 10:39 
QuestionSorting and ResetContent Pin
rhfritz123-Feb-18 3:07
rhfritz123-Feb-18 3:07 
QuestionIssue with Code Analysis Pin
Andrew Truckle20-Dec-16 6:25
professionalAndrew Truckle20-Dec-16 6:25 
QuestionBug found Pin
Member 1134851323-Jan-15 5:31
Member 1134851323-Jan-15 5:31 
QuestionWINVER 0x0400 not compiling Pin
AberAber22-Dec-14 15:29
AberAber22-Dec-14 15:29 
QuestionGood Job, just a couple of suggestions Pin
Guglielmo Calligaro14-Feb-13 0:05
Guglielmo Calligaro14-Feb-13 0:05 
GeneralMy vote of 4 Pin
Victor Nijegorodov5-Aug-12 23:39
Victor Nijegorodov5-Aug-12 23:39 
GeneralRe: My vote of 4 Pin
simonchen.net7-Aug-12 23:31
simonchen.net7-Aug-12 23:31 
Yes, maybe you 're right. I didn't practice this method, but thought if you handle TTN_NEEDTEXT message and EnableToolTip, you will also need to focus on each separated controls - editbox, listbox, combobox.., well, if you want to custom the tip text for each item in dropped list box, it's not easier to realize through handling TTN_NEEDTEXT message. Smile | :)
GeneralMy vote of 5 Pin
onnlv11-Jun-12 19:22
onnlv11-Jun-12 19:22 
GeneralRe: My vote of 5 Pin
simonchen.net30-Jul-12 2:24
simonchen.net30-Jul-12 2:24 
QuestionTooltips and Combo Items different? Pin
symreds17-Oct-11 3:51
symreds17-Oct-11 3:51 
AnswerRe: Tooltips and Combo Items different? Pin
simonchen.net20-Nov-11 2:17
simonchen.net20-Nov-11 2:17 
General64 bit machine Pin
li123427-Oct-09 18:36
li123427-Oct-09 18:36 
GeneralRe: 64 bit machine Pin
simonchen.net23-May-11 23:27
simonchen.net23-May-11 23:27 
GeneralGetting error with COMBOBOXINFO . included "winuser.h" but problem still persist Pin
Elsie17-Sep-09 5:55
Elsie17-Sep-09 5:55 
GeneralRe: Getting error with COMBOBOXINFO . included "winuser.h" but problem still persist Pin
Elsie17-Sep-09 6:10
Elsie17-Sep-09 6:10 
GeneralNo tooltips for DropList Pin
Guido van den Berg23-Jun-09 4:27
Guido van den Berg23-Jun-09 4:27 
GeneralRe: No tooltips for DropList Pin
simonchen.net22-Jul-09 17:34
simonchen.net22-Jul-09 17:34 
GeneralIssue in the Latest Windows OS Pin
Md Saleem Navalur20-May-09 4:47
Md Saleem Navalur20-May-09 4:47 
GeneralRe: Issue in the Latest Windows OS [modified] Pin
Md Saleem Navalur26-May-09 0:00
Md Saleem Navalur26-May-09 0:00 
GeneralRe: Issue in the Latest Windows OS Pin
simonchen.net22-Jul-09 17:43
simonchen.net22-Jul-09 17:43 
GeneralRe: Issue in the Latest Windows OS Pin
ranxiaowu4-Jan-10 21:18
ranxiaowu4-Jan-10 21:18 
GeneralBinary or C#/VB.NET version Pin
manishkjain16-Jan-08 8:34
manishkjain16-Jan-08 8:34 
QuestionHow to create this CTTComboBox dynamically? Pin
KylixLee8-Nov-06 21:15
KylixLee8-Nov-06 21:15 
AnswerRe: How to create this CTTComboBox dynamically? Pin
simonchen.net11-Nov-06 3:08
simonchen.net11-Nov-06 3:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.