Multi-line Tooltip for embedded ActiveX

I have a CFormView-derived class which contains an ActiveX. ActiveX displays a diagram and,unfortunately, supports only one-line tooltips. How can I implement multi-line tooltips for this ActiveX? Tooltip should appear every time mouse pause over a diagram node. Given mouse coordinates ActiveX provides info whether mouse is over node or not, and it is possible to shut off ActiveX own tooltips.
I can provide additional info and rise points if necessary.
polyanovskyAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

AndyAinscowFreelance programmer / ConsultantCommented:
Have you tried "Line 1\r\nLine 2" as the tip to display?
0
AndyAinscowFreelance programmer / ConsultantCommented:
You might also require
m_tip.SetMaxTipWidth(300);   //m_tip is your tooltip control, set your width here

I seem to recall without setting the width the tips will always try to be on one line
0
polyanovskyAuthor Commented:
"Line 1\r\nLine 2" does not work.
I do not have access to ActiveX tooltip control. Changes in CFormView tooltip control does not affect ActiveX tooltip behaviour.
0
Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

AndyAinscowFreelance programmer / ConsultantCommented:
<I do not have access to ActiveX tooltip control.>
Can you supress the default tooltip and provide your own?
0
polyanovskyAuthor Commented:
"it is possible to shut off ActiveX own tooltips". However, there is no way to pass a pointer to my tooltip to ActiveX. Probably, everything should be done at the ActiveX parent window level.
0
AndyAinscowFreelance programmer / ConsultantCommented:
What I meant was stop the ActiveX tooltip completely and supply your own tip from your view.  (From what you write I believe you are handling a callback from the ActiveX for the text to display)
0
polyanovskyAuthor Commented:
   I do not handle a callback from ActiveX for the text to display as it is not provided by ActiveX. Tooltip text is a node property and can not be supplied "on demand". However, I can stop the ActiveX tooltip completely.
    You should think about ActiveX as a "black box". The only info it provides - coordinates of the nodes. Thus I have to create a tooltip on CFormView level which would appear when mouse enters specific rectangles on ActiveX diagram and disappears when mouse leaves those rectangles. Each rectangle will have specific text to display. In this sense there is no difference between ActiveX and a picture where different tooltips should appear when mouse hovers over different parts of the picture.
0
AndyAinscowFreelance programmer / ConsultantCommented:
Create a tooltip for the complete view, check if the mouse is over a 'node' and display tip else hide tip.

      m_tooltip.AddTool(this, LPSTR_TEXTCALLBACK, &rc, 1);   //tooltip, callsback for text to be displayed, rc is the rectangle to tip over - your activeX control in this case

In the OnTooltipNotify (callback for text) check if it is over a node, return false if you don't want to display text.


BOOL CMyView::OnToolTipNotify( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
.....

TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
 pTTT->lpszText = "Some Text Here";
  return true;
}

BOOL CMyView::PreTranslateMessage(MSG* pMsg)
{
      // CG: The following block was added by the ToolTips component.
      {
            // Let the ToolTip process this message.
            m_tooltip.RelayEvent(pMsg);
      }
    if(pMsg->message == WM_MOUSEMOVE)  //Crude - mouse moved, prompt for new text to display
      {
            m_tooltip.Update();
      }

0
polyanovskyAuthor Commented:
In your scheme if I click on ActiveX diagram tooltip disappears and will not appear until mouse leaves ActiveX and enters again (because tooltip serves ActiveX as a whole rather than individual nodes). Tooltip text is not updated when moving from one node to another. Besides that tooltip is shown outside of ActiveX (but it is, probably, easy to correct).
0
AndyAinscowFreelance programmer / ConsultantCommented:
Don't forget you are attempting to change the behaviour of another element you haven't got the source code for - always full of pitfalls.

Click on ActiveX - Focus is changing?  You might require a mouse hook to make certain your app still gets the mouse move messages.

Text not updating - You probably haven't coded correctly to determine the node it is over.  You get the WM_MOUSEMOVE and tell the tip to update.

Tip outside of ActiveX - again probably a mistake in your code.  (Screen/Client co-ordinate mixup?)
0
polyanovskyAuthor Commented:
I could implement desirable behaviuor as following:

class CMainFrame : public CMDIFrameWnd

BOOL CMainFrame::OnToolTipNotify( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
     static CToolTipCtrl* pToolTip = NULL;
     CToolTipCtrl* ptt= AfxGetThreadState()->m_pToolTip;
     if (ptt != pToolTip) { // new tooltip
         CRect rc(4,4,4,4); // 4 pixel margin
         ptt->SetMargin(&rc);
         ptt->SetTipBkColor( RGB(128,255,128));
         ptt->SetMaxTipWidth(128);
         ptt->SetDelayTime(TTDT_AUTOPOP, SHRT_MAX);
         ptt->SetDelayTime(TTDT_INITIAL, TOOLTIP_DELAY);
       ptt->SetDelayTime(TTDT_RESHOW, TOOLTIP_DELAY);

         pToolTip = ptt;
     }
     return CFrameWnd::OnToolTipText(id, pNMHDR, pResult);
}
class CWfView : public CFormView

void CWfView::OnMouseMoveActiveX(short Button, short Shift, long x, long y)//mouse move handler supplied by ActiveX
{
      // TODO: Add your control notification handler code here
      if(m_ActiveX.IsNewPointedNode(x,y))//ActiveX checks if pointed node has changed
      {
       CToolTipCtrl* ptt= AfxGetThreadState()->m_pToolTip;
       if (ptt)
        ptt->Update();
      }
}

BOOL CWfView::OnToolTipNotify( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
      TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
      CString str=m_ActiveX.GetToolTipText();
      if(!str.IsEmpty())
      {
            strcpy(pTTT->szText,str);
            return TRUE;
      }
      return(FALSE);
}

The only remaining problem is  "if I click on ActiveX diagram tooltip disappears and will not appear until mouse leaves ActiveX and enters again ". I guess it is because AfxGetThreadState()->m_pToolTip is NULL after a mouse click untill mouse leaves ActiveX and enters it again.
Tooltip stays at the outer ActiveX border but it should be easy to correct.
I would award all points for resolving just the remaining problem.
0
DanRollinsCommented:
An additional, generic technique:  
Use Spy++ to examine the messages being sent as you move the mouse outside of and inside of the control, before and after clicking, with and without the "default" tooltip handling enabled.  Often times, I've found that Spy++ provides the clue that makes it obvious how to get something done.

-- Dan
0
polyanovskyAuthor Commented:
O-o-ops
Missed two more relevant lines of code:

void CWfView::OnInitialUpdate()
{
      CFormView::OnInitialUpdate();
      
        m_ActiveX.SetShowToolTip(FALSE);
      EnableToolTips(TRUE);
}
0
AndyAinscowFreelance programmer / ConsultantCommented:
A couple of things to try.

Put a TRACE into the OnMouseMoveActiveX function - is it being called after the click on the ActiveX control?

Don't use the generic tooltip control.  Create your own as a member of your frame window - this should always be non-null.

If neither work you might have to write a mouse hook so your app can see the mouse messages even when the focus is on the ActiveX control.
0
polyanovskyAuthor Commented:
Tried the following implementation:

class CWfView : public CFormView
{
private:
      CToolTipCtrl m_ToolTip;
}

void CWfView::OnInitialUpdate()
{
    CFormView::OnInitialUpdate();
    CRect Rect;
    GetClientRect(Rect);
    Rect.DeflateRect(20,20,20,20);//easy to check that ActiveX is properly displayed
    m_ActiveX.MoveWindow(Rect);
    m_ActiveX.SetShowToolTip(FALSE);
//  EnableToolTips(TRUE);
    m_ToolTip.Create(this);
    CRect rc(4,4,4,4); // 4 pixel margin
    m_ToolTip.SetMargin(&rc);
    m_ToolTip.SetTipBkColor( RGB(128,255,128));
    m_ToolTip.SetMaxTipWidth(128);
    m_ToolTip.SetDelayTime(TTDT_AUTOPOP, SHRT_MAX);
    m_ToolTip.SetDelayTime(TTDT_INITIAL, TOOLTIP_DELAY);
    m_ToolTip.SetDelayTime(TTDT_RESHOW, TOOLTIP_DELAY);
    m_ToolTip.AddTool(this,"GHGHHDF", &Rect, 1);
    m_ToolTip.Activate(TRUE);
}

BOOL CWfView::PreTranslateMessage(MSG* pMsg)
{
      // TODO: Add your specialized code here and/or call the base class
      m_ToolTip.RelayEvent(pMsg);
      TRACE("\nPreTranslate()");
      return CFormView::PreTranslateMessage(pMsg);
}

BOOL CWfView::OnToolTipNotify( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
     TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
     CString str=m_ActiveX.GetToolTipText();
     if(!str.IsEmpty())
     {
          strcpy(pTTT->szText,str);
          return TRUE;
     }
     return(FALSE);
}


All tooltip related code is erased in CMainFrame.

Tooltip "GHGHHDF" does not show up. If uncomment EnableToolTips(TRUE) default tooltip appears for ActiveX as a whole with the text provided by CWfView::OnToolTipNotify.
PreTranslateMessage is called as expected, e.g. on mouse move over ActiveX.

0
AndyAinscowFreelance programmer / ConsultantCommented:
excerpt from earlier post

BOOL CMyView::PreTranslateMessage(MSG* pMsg)
{
     // CG: The following block was added by the ToolTips component.
     {
          // Let the ToolTip process this message.
          m_tooltip.RelayEvent(pMsg);
     }
    if(pMsg->message == WM_MOUSEMOVE)  //Crude - mouse moved, prompt for new text to display  <<<------------------
     {
          m_tooltip.Update();
     }
0
polyanovskyAuthor Commented:
Adding

if(pMsg->message == WM_MOUSEMOVE)  //Crude - mouse moved, prompt for new text to display  <<<------------------
     {
          m_tooltip.Update();
     }

to CWfView::PreTranslateMessage does not change anything as tooltip has static text (nevertheless I tried it, but tooltip does not show up anyway).
0
DanRollinsCommented:
My guess is that the ActiveX control is eating the mouse-moves and other messages.

Your first effort would be to make sure that the tips work exactly as desired everywhere else (except for over the ActiveX control).  Once that is done, you can try a couple of other things like:
  1) disable the control to see if that allows tips to pop
  2) create a transparent window over the control to see if that lets the tips pop.

I'm not saying that either is a viable complete solution... only that learning what happens in those situations will pave the way for finding a real solution.

-- Dan
0
AndyAinscowFreelance programmer / ConsultantCommented:
You might require a mouse hook.

When you hook the mouse your app will be given a chance to look at mouse messages even if it doesn't have the focus.  You could then check if the mouse is over the control (and your app should be giving tips) and show the tip with the appropriate text.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
polyanovskyAuthor Commented:
Getting mouse messages is not a problem here - as I mentioned before OnMouseMoveActiveX handler is supplied by ActiveX and is working fine, i.e. is called whenever mouse is moving. Also default (i.e. application supplied)tooltip appears with no problem when mouse is over ActiveX. The only problem with default tooltip is that it is destroyed after the mouse click on ActiveX and is not created until mouse leaves ActiveX and enters it again as it serves ActiveX as a whole. Embedded tooltip does not show up for ActiveX.

I found that http://www.codeproject.com/miscctrl/xinfotip.asp
tooltip gives enough degree of flexibility to implement desired behaviour. I used its Show and Hide methods on appropriate events (mouse move over ActiveX, mouse click, ActiveX scroll, and mouse leaving ActiveX)in order to simulate default tooltip behaviour.
In order to catch when mouse is leaving a window I used a timer. In timer handler I use GetCursorPos and check whether it is in the window rectangle. Is there more elegant way of knowing that mouse is leaving window rectangle (may be application-supplied event)?
Andy,
Thank you very much for your time. I appreciate your help and stimulating discussion.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.