Tooltip for disabled controls
Posted
by Ran Almog
on August 5th, 1998
Tooltip Handler (located in TooltipHandler.h/cpp) is a utility function that handles MFC bug - disabled controls don't show tooltip. All that the programmer has to do is overwrite PreTranslateMessage() of the dialog box class, and to pass to the handler an array of the controls that may be disabled, a number of controls in the array and a pointer to the tooltip class - and it works !
Header file
#ifndef _TOOLTIP_HANDLER_H #define _TOOLTIP_HANDLER_H #include <afxcmn.h> // This function is a patch that overcomes MFC bug of // tooltips that don't show up on in disabled controls // if modal dialogs. Call this function in your overidable of // PreTranslateMessage, before calling the inherited one. void HandleTooltipsActivation(MSG *pMsg, CWnd *This, CWnd *disabledCtrls[], int numOfCtrls, CToolTipCtrl *pTooltip); #endif
CPP file
#include "TooltipHandler.h"
void HandleTooltipsActivation(MSG *pMsg, CWnd *This, CWnd *disabledCtrls[], int numOfCtrls, CToolTipCtrl *pTooltip)
{
CRect rect;
POINT pt;
HWND hWnd = pMsg->hwnd;
LPARAM lParam = pMsg->lParam;
//---------------------------------------------------------------------------
// Disabled control do not show tool tips, in modal dialog
//
//
// The hwnd of the WM_MOUSEMOVE above a disabled control
// is the hWnd of the Dialog itself, this confuse the tooltip
//
// To correct this, if we get WM_MOUSEMOVE and the hwnd is the dialog's hwnd
//
// We check on all the controls that are Visible, but disabled if the point is in their
// rectangle.
//
// In this case we alter the msg to the controls hWnd and coordinates before
// Relaying it to the toolTip control
//----------------------------------------
if( (pMsg->message == WM_MOUSEMOVE) && (pMsg->hwnd == This->m_hWnd)) {
//---------------------------
// The point is in the dialog
// client coordinates
//---------------------------
pt.x = LOWORD(pMsg->lParam); // horizontal position of cursor
pt.y = HIWORD(pMsg->lParam); // vertical position of cursor
for (int i = 0; i < numOfCtrls; i++) {
//---------------------------------
// rect is the control rectangel in
// Dialog client coordinates
//----------------------------------
disabledCtrls[i]->GetWindowRect(&rect);
This->ScreenToClient(&rect);
if(rect.PtInRect(pt) ) {
//----------------------------------------------------------------
// The mouse is inside the control
//
// 1. We change the Msg hwnd to the controls hWnd
// 2. We change the Msg lParam to the controls client coordinates
//
//----------------------------------------------------------------
pMsg->hwnd = disabledCtrls[i]->m_hWnd;
This->ClientToScreen(&pt);
disabledCtrls[i]->ScreenToClient(&pt);
pMsg->lParam = MAKELPARAM(pt.x, pt.y);
break;
}
}
}
//---------------------------------------
// Relay the msg to the tool tip control
//---------------------------------------
pTooltip->RelayEvent(pMsg);
pTooltip->Activate(TRUE);
//--------------------------------------
// Restore the original msg
//--------------------------------------
pMsg->hwnd = hWnd;
pMsg->lParam = lParam;
}

Comments
Sample helper code, how to get all disabled controls into array
Posted by Legacy on 05/13/2003 12:00amOriginally posted by: Conrad Braam
OK, so not all of us can build an array of disabled controls, below follows the code to do just that. In your dialog H file add these members...
int m_numDisabledControls;
CWnd *m_pDisabledControls[256]; //only can get 256 controls
...Then into your OnInitdialog (+ any other time U change control enable states)
// enumerate all controls in this window
CWnd *pChildFirst,*pChild;
m_numDisabledControls = 0;
pChildFirst = GetWindow(GW_CHILD);
pChild = pChildFirst;
while (TRUE)
{
if (!pChild->IsWindowEnabled())
{
m_pDisabledControls[m_numDisabledControls] = pChild;
m_numDisabledControls++;
}
pChild = pChild->GetNextWindow(GW_HWNDNEXT);
if ((pChildFirst == pChild)||(NULL==pChild))
break;
}
..also remember to init m_numDisabledControls to Zero in your constructor to prevent bugs
m_numDisabledControls = 0;
A little note on why I have only space for 256 disabled controls. :
It appears, that the windows dialog template only allows 256 controls, this is a windows limitation, and the only ways to bypass it I know of, involve adding controls to a window at runtime.
Enjoy.
ReplyCToolTipCtrlEx
Posted by Legacy on 12/20/2002 12:00amOriginally posted by: Vladimir Belinkis
Very good idea, I used it and created a class CToolTipCtrlEx.
Overide 3 functions: Create,AddTool,RelayEvent.
BOOL CYourDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_MOUSEMOVE)
{
// pass a mouse message to a tool tip control for processing
// m_ToolTipCtrl is CToolTipCtrlEx
m_ToolTipCtrl.RelayEvent(pMsg);
}
return CDialog::PreTranslateMessage(pMsg);
}
class CToolTipCtrlEx : public CToolTipCtrl
{
.......
void RelayEvent( LPMSG lpMsg );
BOOL AddTool( CWnd* pWnd, LPCTSTR lpszText = LPSTR_TEXTCALLBACK, LPCRECT lpRectTool = NULL, UINT nIDTool = 0 );
BOOL Create( CWnd* pParentWnd, DWORD dwStyle = 0 );
protected:
CWnd* m_wndParent; // usually dialog
CList <CWnd*, CWnd*> m_ToolList;
};
BOOL CToolTipCtrlEx::Create(CWnd *pParentWnd, DWORD dwStyle)
{
m_wndParent = pParentWnd;
// call base class
BOOL bRet = CToolTipCtrl::Create(pParentWnd, dwStyle);
return bRet;
}
BOOL CToolTipCtrlEx::AddTool( CWnd* pWnd, LPCTSTR lpszText, LPCRECT lpRectTool, UINT nIDTool)
{
POSITION pos = m_ToolList.AddTail(pWnd);
if (!pos)
{
return FALSE;
}
// call base class
BOOL bRet = CToolTipCtrl::AddTool(pWnd, lpszText,lpRectTool,nIDTool);
return bRet;
}
void CToolTipCtrlEx::RelayEvent(LPMSG pMsg)
{
if (pMsg->message != WM_MOUSEMOVE || pMsg->hwnd != m_wndParent->m_hWnd)
{
// call base class
CToolTipCtrl::RelayEvent(pMsg);
return;
}
// mouse moved over parent
// if control is disabled show tool tip anyway
// pass changed message to a tool tip control for processing
MSG myMsg;
::CopyMemory(&myMsg, pMsg, sizeof(MSG));
CPoint pt;
CRect rect;
pt.x = LOWORD(pMsg->lParam); // horizontal position of cursor
pt.y = HIWORD(pMsg->lParam); // vertical position of cursor
POSITION pos = m_ToolList.GetHeadPosition();
while (pos != NULL)
{
CWnd* pWndIter = m_ToolList.GetNext(pos);
pWndIter->GetWindowRect(&rect);
m_wndParent->ScreenToClient(&rect);
if (rect.PtInRect(pt) )
{
//----------------------------------------------------------------
// The mouse is inside the control
//
// 1. We change the Msg hwnd to the controls hWnd
// 2. We change the Msg lParam to the controls client coordinates
//
//----------------------------------------------------------------
myMsg.hwnd = pWndIter->m_hWnd;
m_wndParent->ClientToScreen(&pt);
pWndIter->ScreenToClient(&pt);
myMsg.lParam = MAKELPARAM(pt.x, pt.y);
// pass the changed message to the base class
CToolTipCtrl::RelayEvent(&myMsg);
return;
}
}
Reply// pass the changed message to the base class
CToolTipCtrl::RelayEvent(pMsg);
}
can u help me?????????
Posted by Legacy on 02/25/2000 12:00amOriginally posted by: Prafull surana
i have some geometric shapes on my view. I want to display a tool tip stating its name when ever mouse comes over it. How can i do it. Please Help Me.
ReplyA sample ?
Posted by Legacy on 02/18/2000 12:00amOriginally posted by: Cyril Boutamine
Anyone have a sample with cbitmapdialog ?
Thanks,
ReplyCyril Boutamine
Manually Displaying Tooltips in Windows
Posted by Legacy on 01/24/2000 12:00amOriginally posted by: Jake Wolf
I am trying to get a tooltip to show up without mouse movement. Specifically, I want a tooltip to show up when certain dialog controls get the keyboard focus. As near as I can tell, there is no simple way to do this (although it is easy to remove a tooltip that is already showing). I have no problem getting tooltips to show up when the mouse is over the specified controls. I have even tried sending fake mouse messages to the tooltip control, but it's not fooled. Any ideas?
Reply