【问题标题】:Tracking tooltip in CScrollView?CScrollView 中的跟踪工具提示?
【发布时间】:2017-08-08 22:18:38
【问题描述】:

在标准 C++/MFC MDI 文档/视图项目中,我想在视图中实现跟踪工具提示(通常占据主框架窗口大部分的选项卡式视图窗口)。所以,在课堂MyAppView,我有一个成员CToolTipCtrl tooltip。函数MyAppView::OnInitialUpdate() 包含初始化

BOOL ok0 = tooltip.Create(this, TTS_ALWAYSTIP);
CRect clientRect; GetClientRect(&clientRect);
BOOL ok2 = tooltip.AddTool(this, LPSTR_TEXTCALLBACK, &clientRect, 1234/*tool ID*/);
tooltip.Activate(TRUE);

使视图的整个客户区成为“工具”。消息映射包含一个条目

ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnNeedToolTipText)

函数OnNeedToolTipText定义为

BOOL MyAppView::OnNeedToolTipText(UINT id, NMHDR *pNMHDR, LRESULT *pResult)
{
    UNREFERENCED_PARAMETER(id);

    NMTTDISPINFO *pTTT = (NMTTDISPINFO *)pNMHDR;
    UINT_PTR nID = pNMHDR->idFrom;
    BOOL bRet = FALSE;
    if(nID == 1234)
    {
        // Come here when text is needed for tracking tooltip
    }
    if(pTTT->uFlags & TTF_IDISHWND)
    {
        // idFrom is actually the HWND of the tool
        nID = ::GetDlgCtrlID((HWND)nID);
        if(nID)
        {
            _stprintf_s(pTTT->szText, sizeof(pTTT->szText) / sizeof(TCHAR),
              _T("Control ID = %d"), nID);
            pTTT->hinst = AfxGetResourceHandle();
            bRet = TRUE;
        }
    }

    *pResult = 0;

    return bRet;
}

仅将鼠标放在菜单项(文件、编辑、视图、窗口、帮助)上会导致代码输入OnNeedToolTipText,ID 为 0-5。将鼠标移到客户区(视图)中没有任何作用。

如何让工具提示仅显示在视图的客户区?

Visual Studio 2017; C++; 64 位 Windows 7

【问题讨论】:

  • 我已经检查了我的观点之一。我没有创建工具提示。我只 EnableToolTips( ) 让 MFC 完成剩下的工作。提示跟随我的鼠标。
  • @lakeweb:我尝试删除工具提示成员和Create 等,并在MyAppView::OnInitialUpdate 中添加EnableToolTips(TRUE);,我得到与以前相同的结果:工具提示仅在菜单上吧。

标签: c++ mfc tooltip mdi docview


【解决方案1】:

为了解决问题,您需要执行以下操作:

BOOL CMyAppView::PreTranslateMessage(MSG* pMsg)
{
    switch (pMsg->message)
    {
    case WM_KEYDOWN:
    case WM_SYSKEYDOWN:
    case WM_LBUTTONDOWN:
    case WM_RBUTTONDOWN:
    case WM_MBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_RBUTTONUP:
    case WM_MBUTTONUP:
    case WM_MOUSEMOVE:
        if (m_pToolTip->GetSafeHwnd () != NULL)
        {
            m_pToolTip->RelayEvent(pMsg);
        }
        break;
    }

    return CScrollView::PreTranslateMessage(pMsg);
}

【讨论】:

    【解决方案2】:

    如果您想在视图中显示跟踪工具提示,请按照以下步骤操作:

    创建工具提示并添加工具。

    void CToolTipDemoView::OnInitialUpdate()
    {
        // ...
    
        m_toolTip.Create(this, TTS_ALWAYSTIP | TTS_NOANIMATE);
        m_toolTip.AddTool(this, _T("Doesn't matter"));
    }
    

    处理 WM_MOUSEMOVE 消息。首先,调用 _TrackMouseEvent 以进一步接收 WM_MOUSELEAVE 并激活工具提示。其次,更新工具提示文本,并在鼠标指针坐标处显示。

    void CToolTipDemoView::OnMouseMove(UINT nFlags, CPoint point)
    {
        if (!m_bTrackingMouseLeave)
        {
            TRACKMOUSEEVENT tme = { 0 };
            tme.cbSize = sizeof(TRACKMOUSEEVENT);
            tme.dwFlags = TME_LEAVE;
            tme.hwndTrack = m_hWnd;
            ::_TrackMouseEvent(&tme);
    
            m_toolTip.Activate(TRUE);
            m_bTrackingMouseLeave = TRUE;
        }
    
        if (m_pointLastMousePos != point)
        {
            CString strText;
            strText.Format(_T("x = %d y = %d"), point.x, point.y);
            m_toolTip.UpdateTipText(strText, this);
            m_toolTip.Popup();
            m_pointLastMousePos = point;
        }
    
        CScrollView::OnMouseMove(nFlags, point);
    }
    

    处理 WM_MOUSELEAVE 并停用工具提示。

    void CCToolTipDemoView::OnMouseLeave()
    {
        m_bTrackingMouseLeave = FALSE;
    
        // mouse pointer leaves the window so deactivate the tooltip
        m_toolTip.Activate(FALSE);
    
        CScrollView::OnMouseLeave();
    }
    

    注意事项:

    • 不再需要处理 TTN_NEEDTEXT。
    • 另外,没有必要重写 PreTranslateMessage

    【讨论】:

      【解决方案3】:

      所以我回去看看我可能会错过什么。我在 10 多年前写了这些东西。我还覆盖了一个 CWnd 成员

      virtual INT_PTR OnToolHitTest( CPoint point, TOOLINFO* pTI ) const;
      

      与:

      INT_PTR HERichView::OnToolHitTest( CPoint point, TOOLINFO* pTI ) const
      {
          pTI->hwnd = m_hWnd;
          pTI->uId = point.x + ( point.y << 16 );
          CRect rect;
          GetClientRect( rect );
          pTI->rect= rect;
          pTI->lpszText= LPSTR_TEXTCALLBACK;
          return pTI->uId;
      }
      

      我查了一下,没有这个就不行。所以你的:

      ON_NOTIFY_EX( TTN_NEEDTEXT, 0, OnToolTip )
      

      如果您添加上述内容,则应该调用。并且只需要EnableToolTips( );

      【讨论】:

      • 我将代码更改为在OnInitialUpdate 中包含EnableToolTips(),并添加了您使用的虚拟OnToolHitTest 代码。我得到了命中测试,但没有TTN_NEEDTEXT 通知,所以它不起作用。顺便说一句,您的代码中有一个小错误;在 (0,0) 点,命中测试将返回 false。
      • 我不知道为什么它对你不起作用。我已经追踪了代码,没有更多内容了。 OnToolHitTest 返回一个点为 HI,LOW 整数,它不返回 BOOL。 0,0 是一个有效点。 -1 用于取消。没有断点的测试,我确实看到如果使用断点它是行不通的。
      • technet.microsoft.com/en-us/library/xbwysc9f(v=vs.120).aspx 是我在OnToolHitTest 上可以找到的最新文档;它表示返回值“如果找到工具提示控件,则为窗口控件 ID。如果未找到工具提示控件,则为 -1。”我会尝试不设置断点。
      • 嗨伍迪,这很有趣。追踪并到达:if (pModuleThreadState-&gt;m_nLastHit != nHit...。如果获取控件的 ID,则提示会相应更改。在这种情况下,我们希望提示随着移动而改变,因此返回命中点会触发新的工具提示。如果有人想像我们一样使用它,也许 -1 取消是一个提前的想法?那是很久以前的事了,我什至不知道我是否解决了这个问题。
      【解决方案4】:

      我没有成功让跟踪工具提示在 MFC 中工作。我最接近的是

      在消息映射中:ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnNeedToolTipText)

      OnInitialUpdateBOOL ok1 = EnableTrackingToolTips(TRUE);

      在覆盖虚函数OnToolHitTest

          pTI->hwnd = m_hWnd;
          pTI->uId = (UINT_PTR)m_hWnd;
          pTI->uFlags = TTF_IDISHWND | TTF_ALWAYSTIP | TTF_TRACK | TTF_NOTBUTTON | TTF_ABSOLUTE | TTF_SUBCLASS;
          pTI->lpszText = LPSTR_TEXTCALLBACK;
          return pTI->uId;
      

      OnNeedToolTipText:

      NMTTDISPINFO *pTTT = (NMTTDISPINFO *)pNMHDR;
      UINT_PTR nID = pNMHDR->idFrom;
      BOOL bRet = FALSE;
      if(pTTT->uFlags & TTF_IDISHWND)
      {
          // idFrom is actually the HWND of the tool
          nID = ::GetDlgCtrlID((HWND)nID);
          if(nID)
          {
              CURSORINFO ci; ci.cbSize = sizeof(CURSORINFO); // get something interesting to display
              GetCursorInfo(&ci);
              _stprintf_s(pTTT->szText, sizeof(pTTT->szText) / sizeof(TCHAR),
                  _T("Control ID = %lld at (%d, %d)"), nID, ci.ptScreenPos.x, ci.ptScreenPos.y);
              pTTT->hinst = AfxGetResourceHandle();
              bRet = TRUE;
          }
      }
      *pResult = 0;
      return bRet;
      

      这会产生以下特殊行为。当我启动应用程序并将鼠标光标移动到 CScrollView 的客户区域时,光标旁边会出现一个工具提示。

      如果我小心(平稳地)移动鼠标,工具提示会正确跟踪。但过了一会儿,它消失了,并且没有进一步的鼠标移动,包括离开 CScrollView 窗口并返回,让它重新出现。

      我认为正在发生的事情是,当鼠标光标移动到工具提示窗口上时,工具提示会永久关闭。这种消失似乎与时间无关(例如,由于自动弹出);如果鼠标保持不动,则工具提示将无限期保留。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-01-24
        • 1970-01-01
        • 1970-01-01
        • 2015-08-21
        • 2011-08-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多