Neat Tooltip for Combobox

Download source files - 6 Kb
Download demo project - 19 Kb

Introduction


I have been ever perplexed by the question which's tool-tip associated with Combo-box,
On the internet I have searched lots of samples about this but these samples look like so complex, some samples that have wrapped the Combo-box using separated controls 'CListbox', 'CEdit', 'CButton', so that corresponding to generate many extra class for the Combo-box that lots of work to maintain the Combo-box. A couple of samples has using hooks for window subclassing that all messages go to new WindowProc(window procedure) before going to the combobox, ummm..., that's very useful. but they still don't be enough simply, thus base upon these samples I have wrapped a enhanced class CTTCombobox, According to expectation there use the new WindowProc to hold up the List-box's messages
and to do too-tip things. BTW, for the enhanced class CTTCombobox, the source files only contain 'TTCombobox.h' and 'TTCombobox.cpp',
that's very easy to embed into your VC++ project.

Noteworthy

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

To use

1. The class CTTComboBox is derive from MFC class CCombobox, you can immediately use the class CTTComboBox as well as make new class derive from it.
2. Default, the too-tip is allowed for the combobox(instance with the class CTTComboBox), to enable/disable the too-tip, you need to perform the SetToolTip function before creating or subclassing combobox, details see attached demo project.
3. Using SetToolTipDelay function to set up the appropriate delayed time for show the tool-tip window.

Implementation

As mention above, default the tool-tip is allowed mean m_isEnableTool is TRUE, see codes as follows:

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 perform CreateTooltipWnd function that will createa tool-tip window
(note: all combobox with same class CTTComboBox has share a tool-tip window), then we have install hook for subclassing the list-box and edit-box portion of the combobox, see InstallHookForListboxAndEditbox function:

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 list-box and edit-box, then the SetWindowLong function creates the list-box and edit-box subclass, causing the system to call the new window procedure instead of the previous one, a trick that's all previous(old) window proceduce have been add to map, later we will reuse the old window procedure in new window procedure, such as window proceduce - HookListboxWndProc with the list-box:
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 function ending, we have reuse the old window proceduce via call CallWindowProc function from the map that like chain of window procedures. some messages have been reprocessed for the list-box, In processing the WM_MOUSEMOVE, the HandleListboxMouseMove function determine whether or not the tool-tip window is shown/hidden and the OnTrackMouseEvent function track mouse event messages WM_MOUSEHOVER or WM_MOUSELEAVE, that aim to reset original select of the list-box when fire up WM_MOUSELEAVE, waiting..., the WM_MOUSELEAVE message take continuous place but the mouse cursor still is above the list-box, Actually, the mouse cursor is above the tool-tip window when the tool-tip window show up, think over? so we must capture the list-box to prevent this, to release the mouse capture that only when the tool-tip has been hidden.
Specially, The combobox with owner DropList or DropDown style has a litte trouble, when release the mouse capture, the list-box became invisible.
thus I have hold the WM_CAPTURECHANGED and ignore the message...

Usage

you are allowed to use it for free and further modify it.

你可能感兴趣的:(thread,windows,mfc,UP,vc++)