Tooltip for disabled controls

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:00am

    Originally 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.

    Reply
  • CToolTipCtrlEx

    Posted by Legacy on 12/20/2002 12:00am

    Originally 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;
    }
    }


    // pass the changed message to the base class
    CToolTipCtrl::RelayEvent(pMsg);

    }

    Reply
  • can u help me?????????

    Posted by Legacy on 02/25/2000 12:00am

    Originally 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.

    Reply
  • A sample ?

    Posted by Legacy on 02/18/2000 12:00am

    Originally posted by: Cyril Boutamine

    Anyone have a sample with cbitmapdialog ?

    Thanks,
    Cyril Boutamine

    Reply
  • Manually Displaying Tooltips in Windows

    Posted by Legacy on 01/24/2000 12:00am

    Originally 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
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date