Link to home
Start Free TrialLog in
Avatar of mrwad99
mrwad99Flag for United Kingdom of Great Britain and Northern Ireland

asked on

Tooltips: tracking and working for disabled controls - how?

Ah hello.

I have a very simple dialog application, and am trying to accomplish two tasks with tooltips:

1 ) Get the tooltip to track with the mouse movement,i.e. follow the mouse cursor around, as long as it remains on the same control.
2) Get the tooltip to appear on a disabled control.

I have uploaded my simple project (VS2003, for maximum compatibility :)) to http://www.yousendit.com/download/bVlBWGJDd0lCSWRFQlE9PQ, please download it and take a look.

FYI, here is the code I am using to create and display the tooltip:

BOOL CEE_Tooltip_QDlg::OnInitDialog()
{
      CDialog::OnInitDialog();

      VERIFY ( m_wndTooltip.Create ( this ) );

      VERIFY ( m_wndTooltip.AddTool ( GetDlgItem ( IDC_MYCONTROL ), LPSTR_TEXTCALLBACK ) );
      VERIFY ( m_wndTooltip.AddTool ( GetDlgItem ( IDC_EDIT1 ), LPSTR_TEXTCALLBACK ) ); // Disabled edit control

      // ...
}

void CEE_Tooltip_QDlg::OnNeedText ( NMHDR* pnmh, LRESULT* pResult )
{
      TOOLTIPTEXT* pttt = ( TOOLTIPTEXT* ) pnmh;
      // If the tooltip that this message has been sent for is our tooltip...
      if ( pttt->hdr.hwndFrom == m_wndTooltip.m_hWnd )
      {
            // Find the string that maps to the window we are displaying the tooltip for ( stored in pttt->hdr.idFrom ).
            m_strTooltipText = _T("This is a long tooltip that has come from CEE_Tooltip_QDlg::OnNeedText");
            pttt->lpszText = ( LPTSTR ) ( LPCTSTR ) m_strTooltipText;
      }
}

Can someone please tell me how to achieve these two tasks?  I simply cannot find anything on the internet about this.

TIA
SOLUTION
Avatar of Castorix
Castorix

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of mrwad99

ASKER

I have searched in numerous places, and none of the code I have found works.

Take this example:

 http://groups.google.com/group/microsoft.public.win32.programmer.ui/browse_thread/thread/2c883f6081350a9a/72afac3b5bc9dc68?lnk=st&q=tracking+tooltip

Following the posted code and recommended change, I still get no tracking tooltip.  No sample on MSDN, codeproject, codeguru or any other site I am familiar with has a *working example* of getting a tooltip to move with the mouse.

If you have seen one, or you know how to solve this, then please do tell.

Thanks.
Avatar of AndyAinscow
Instead of the individual controls have the tooltip linked to the dialog itself.
As the mouse moves around on the dialog you should be able to preview the mouse message, test if the cursor is over a control then show/hide/move the tooltip as required.

(I've had to resort to that myself some time ago - it does work but I don't think it is elegant however).
Avatar of mrwad99

ASKER

OK ok I managed to get the sample athttp://msdn.microsoft.com/en-us/library/bb760252(VS.85).aspx#tooltip_sample_trackingfor tracking tooltips working.  A bit messy but I should be able to tidy it up using CTooltipCtrl instead of the raw Win32 stuff.

Now I just need to get the tooltips to be displayed on disabled controls...

Ideas anyone?
Avatar of mrwad99

ASKER

Hi Andy!

Long time no, er, type!  I hope you are well.

Yeah, that is what the sample at MSDN does (the tooltip tracks over the whole dialog); I was just thinking how to get it to work for individual controls who have had tooltips added via CTooltipCtrl::AddTool()...

The first thought I had was have a common CWnd derived class from which I derive all controls from, then I can test whether the mouse is over it or not and show/hide appropriately.  Although that might be a little overkill.

I will continue to play; if you can comment on this or on disabled controls then please do.
:-)   Fine, thanks.

I think you will have problems with disabled controls - if I remember correctly they will not get mouse messages (a feature of windows ?).
Just have a customised control eg. CEdit based with a mouse move handler and a TRACE statement.  When it is disabled you will not have any output from the TRACE.  As you don't get any mouse messages then the native (MFC) tooltip will not be displayed.



<You could try to make a 'helper' class which wraps the tooltip and maintains a collection of windows/rects - only a few lines of code in each dialog to implement it, most of which would be like the default tooltip code>
Avatar of mrwad99

ASKER

OK, that is what I thought you would say.

I have discovered various shortcomings in the MSDN sample.  To start, for an unknown reason the tooltip does not appear initially until the mouse is moved over the dialog then off; when moving it back on for the second time the tracking tooltip appears.

I have circumvented this as follows:

        static BOOL b = FALSE;    // NEW
        if (!g_TrackingMouse)// The mouse has just entered the window.
        {
            // Request notification when the mouse leaves.
            TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT) };
            tme.hwndTrack = hDlg;
            tme.dwFlags = TME_LEAVE;
            TrackMouseEvent(&tme);

            // Activate the ToolTip.
            ::SendMessage(g_hwndTrackingTT, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&g_toolItem);

            // NEW CODE FROM HERE
            g_TrackingMouse = TRUE;
            if ( !b )
            {
                ::SendMessage ( this->m_hWnd, WM_MOUSELEAVE, 0, 0 );
                b = TRUE;
            }
        }

By forcing the tooltip to be deactivated after activation, it appears to work instantly, i.e. the first mouse movement detected displays the tooltip.

I wanted to tidy the MSDN code up using CTooltipCtrl.  So the first thing I did was create myself a CTooltipCtrl

    /*CTooltipCtrl */m_wndTTMSDN.Create ( this, TTF_TRACK | TTF_ABSOLUTE );

and update the global HWND to be the HWND of this object

I found that this did not work.  The problem is in that AddTool, the HWND member of the TOOLINFO structure used internally sets the HWND member to be the parent HWND of the window passed, which is NULL.  So we have to use the MSDN way of constructing the TOOLINFO and calling SendMessage()...

Also, regarding CTooltipCtrl in general, if we look at

_AFXCMN_INLINE void CToolTipCtrl::Activate(BOOL bActivate)
    { ASSERT(::IsWindow(m_hWnd));  ::SendMessage(m_hWnd, TTM_ACTIVATE, bActivate, 0L); }

we see that there is no LPARAM.  The MSDN sample linked to previously uses the following code to activate the tooltip

::SendMessage(g_hwndTrackingTT, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&g_toolItem);

With g_hwndTrackingTT as the HWND of my CTooltipCtrl as above, I cannot replace the SendMessage call with

    m_wndTTMSDN.Activate ( TRUE );

as it does not work; presumably due to the lack of TOOLINFO (indeed, even with SendMessage and 0 as LPARAM, it still fails).

Also,

    m_wndTTMSDN.UpdateTipText ( coords, this );

does not work when setting the text of the tooltip to be the cursor position;

    ::SendMessage(g_hwndTrackingTT, TTM_SETTOOLINFO, 0, (LPARAM)&g_toolItem);

must be used.  Internally, UpdateTipText sends a TTM_UPDATETIPTEXT, not a TTM_SETTOOLINFO...

I post most of the above as a summary of my findings, but do you have any comments anyone?



Avatar of mrwad99

ASKER

Disabled controls tooltips - I have the answer!

http://www.codeguru.com/cpp/controls/controls/tooltipcontrols/article.php/c2277

I had previously came across this but rejected it as it did not work.  The problem was that I had

BOOL CEE_Tooltip_QDlg::PreTranslateMessage(MSG* pMsg)
{
    static CWnd* arrayC [] = { GetDlgItem ( IDC_EDIT1 ) };
    HandleTooltipsActivation ( pMsg, this, arrayC, 1, &m_wndTooltip );
    m_wndTooltip.RelayEvent ( pMsg ); // ARGHHHHHH - SIN CITY!
    return CDialog::PreTranslateMessage(pMsg);
}

where m_wndTooltip is a  tooltip.  The problem was that the call to  m_wndTooltip.RelayEvent ( pMsg ) was stopping the tooltip appearing; without this call it all works just dandy :)

Even more interesting is the idea of wrapping this in a class -

http://www.codeguru.com/cpp/controls/controls/tooltipcontrols/comments.php/c2277/?thread=29452

which handles it all beautifully, simply beautifully!

So after any closing comments I guess I can close this question!
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of mrwad99

ASKER

Sorry Andy I am not with you on that; what part are you referring to?
In the PreTranslateMsg, after calling the RelayEvent of the tip control I called the update.  The tip would then follow the cursor even if I kept the cursor on the same control.
Avatar of mrwad99

ASKER

Now that is interesting; it is effectively a form of tracking tooltip isn't it!  The downside is that if the mouse keeps moving, the tooltip never gets unactivated, even after moving off the control with which it was associated...

Are you aware of this?
It does with me ;-)
Avatar of mrwad99

ASKER

Agreed.  The problem is when I use the custom tooltip class linked to above in the second link; when I have the override of RelayEvent this problem is encountered.  Commenting it out removes the problem.

Any ideas why this is?
>>Any ideas why this is?

No, your guess would be as good as mine.  I would have to study the code of that class AND try to find out just what the CTooltip class::RelayEvent function is doing.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial