【问题标题】:How do I display custom tooltips in a CTreeCtrl?如何在 CTreeCtrl 中显示自定义工具提示?
【发布时间】:2010-09-21 03:42:57
【问题描述】:

我有一个派生自CTreeCtrl 的类。在OnCreate() 中,我将默认的CToolTipCtrl 对象替换为自定义对象:

int CMyTreeCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CTreeCtrl::OnCreate(lpCreateStruct) == -1)
        return -1;

    // Replace tool tip with our own which will
    // ask us for the text to display with a TTN_NEEDTEXT message
    CTooltipManager::CreateToolTip(m_pToolTip, this, AFX_TOOLTIP_TYPE_DEFAULT);
    m_pToolTip->AddTool(this, LPSTR_TEXTCALLBACK);
    SetToolTips(m_pToolTip);

    // Update: Added these two lines, which don't help either
    m_pToolTip->Activate(TRUE);
    EnableToolTips(TRUE);
    
    return 0;
}

我的消息处理程序如下所示:

ON_NOTIFY_EX(TTN_NEEDTEXT, 0, &CMyTreeCtrl::OnTtnNeedText)

但是我从未收到TTN_NEEDTEXT 消息。我用 Spy++ 看了一下,看起来这条消息永远不会被发送。

这可能是什么问题?

更新

我不确定这是否相关:CTreeCtrl 的父窗口类型为 CDockablePane。是否需要一些额外的工作才能使其正常工作?

【问题讨论】:

    标签: c++ mfc tooltip mfc-feature-pack


    【解决方案1】:

    我相信你仍然必须启用工具提示,即使你正在替换内置。

    EnableToolTips(TRUE);
    

    好吧,既然这对你不起作用,而且没有其他专家提供任何帮助,这里还有一些我的建议。虽然它们很蹩脚,但它们可能会让你再次动起来:

    • 确保您的 OnCreate() 循环实际正在执行。
    • 在更换之前启用工具提示。
    • 我用来执行此操作的代码如下所示。 (我承认我不了解所有细节,我从一些示例代码中复制了它,它有效,所以我再也没有看过它。)

      // 启用标准工具提示

      启用工具提示(真);

      // 禁用内置工具提示

      CToolTipCtrl* pToolTipCtrl = (CToolTipCtrl*)CWnd::FromHandle((HWND)::SendMessage(m_hWnd, LVM_GETTOOLTIPS, 0, 0L));

    【讨论】:

    • 这似乎没有任何效果。我将它添加到代码中。连同对 CToolTipCtrl::Activate() 的调用。
    • 感谢您的更新!不幸的是,我在这里没有进一步说明......我验证了 OnCreate() 被调用并且启用工具提示 before 替换似乎没有效果。 SendMessage() 调用也没有。我相信这只会检索一个指针,实际上并没有禁用任何东西。
    • 好吧,真可惜。奇怪的是没有人做出贡献。我只能建议您构建最简单的应用程序以在测试树上显示工具提示,看看是否可行。顺便说一句,Sendmessage() 不仅仅是检索一个指针。
    【解决方案2】:

    尝试专门处理所有工具提示 ID:

    ON_NOTIFY_EX_RANGE(TTN_NEEDTEXT, 0, 0xFFFF, &CMyTreeCtrl::OnNeedTipText)
    

    如果这不起作用,您可能必须从 PreTranslateMessage() 手动调用 RelayEvent()。

    【讨论】:

      【解决方案3】:

      我没有在 CTreeCtrl 中尝试过,但我认为您应该为工具提示 ctrl 调用 RelayEvent 以了解何时必须显示工具提示。试试这个:

      MyTreeCtrl.h:

      virtual BOOL PreTranslateMessage(MSG* pMsg);
      

      MyTreeCtrl.cpp:

      BOOL CMyTreeCtrl::PreTranslateMessage(MSG* pMsg) 
      {
          m_pToolTip.Activate(TRUE);
          m_pToolTip.RelayEvent(pMsg);
      
          return CTreeCtrl::PreTranslateMessage(pMsg);
      }
      

      希望对你有所帮助。

      【讨论】:

      • 在我阅读的一个论坛中,如果控件属于对话框,则必须调用 RelayEvent()。但是,该示例没有提到调用 Activate()。我尝试了您的建议,但仍然没有成功...
      • 很遗憾听到这个消息。正如我告诉你的那样,我既没有尝试过使用 CTreeCtrl 也没有尝试过 CDockablePane。也许如果你能上传申请,我们可以看看。
      【解决方案4】:

      您不必重写 OnToolHitTest() 吗?

      (old) Resource 1

      (old) Resource 2:

      除了返回命中代码 (nHit) 之外,您还必须填写 TOOLINFO 结构。下面是 VIRGIL 在 CMainFrame::OnToolHitTest 中的做法:

       int nHit = MAKELONG(pt.x, pt.y);
       pTI->hwnd = m _ hWnd;
       pTI->uId  = nHit;
       pTI->rect = CRect(CPoint(pt.x-1,pt.y-1),CSize(2,2));
       pTI->uFlags |= TTF _ NOTBUTTON;
       pTI->lpszText = LPSTR _ TEXTCALLBACK;
      

      其中大部分是显而易见的——比如设置 hwnd 和 uId——但有些不是那么明显。我将 rect 成员设置为以鼠标位置为中心的 2 像素宽、2 像素高的矩形。工具提示控件使用这个矩形作为“工具”的边界矩形,我希望它很小,所以将鼠标移动到任何地方都会构成在工具之外移动。我在 uFlags 中设置了 TTF _ NOTBUTTON 因为工具提示与按钮无关。这是 afxwin.h 中定义的特殊 MFC 标志; MFC 使用它为工具提示提供帮助。工具提示还有另一个 MFC 扩展标志,TTF_ALWAYSTIP。如果您希望 MFC 即使在您的窗口未处于活动状态时也显示提示,您可以使用它。 您可能已经注意到,到目前为止,我还没有告诉 MFC 或工具提示或 TOOLINFO 提示的实际文本是什么。这就是 LPSTR _ TEXTCALLBACK 的用途。这个特殊值告诉工具提示控件(MFC 使用的内部线程全局控件)调用我的窗口以获取文本。它通过向我的窗口发送带有通知代码 TTN_NEEDTEXT 的 WM_NOTIFY 消息来实现这一点。

      【讨论】:

      • 我不确定我做错了什么,但我仍然没有收到 TTN_NEEDTEXT 通知...
      【解决方案5】:

      终于!我(部分)解决了它:

      看起来CDockablePane父窗口确实导致了这个问题......

      首先,我从 CTreeCtrl 派生类中删除了所有工具提示特定的代码。一切都在父窗格窗口中完成。

      然后我编辑了父窗口的OnCreate()方法:

      int CMyPane::OnCreate(LPCREATESTRUCT lpCreateStruct)
      {
          if (CDockablePane::OnCreate(lpCreateStruct) == -1)
              return -1;
      
      const DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
          TVS_CHECKBOXES | TVS_DISABLEDRAGDROP | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT |
          TVS_INFOTIP | TVS_NOHSCROLL | TVS_SHOWSELALWAYS;
      
      // TREECTRL_ID is a custom member constant, set to 1
      if(!m_tree.Create(dwStyle, m_treeRect, this, TREECTRL_ID ) )
      {
          TRACE0("Failed to create trace tree list control.\n");
          return -1;
      }
      
      // m_pToolTip is a protected member of CDockablePane
      m_pToolTip->AddTool(&m_tree, LPSTR_TEXTCALLBACK, &m_treeRect, TREECTRL_ID);
      m_tree.SetToolTips(m_pToolTip);
      
      
      return 0;
      

      }

      不幸的是,我们不能简单地用更少的参数调用AddTool(),因为如果没有设置工具ID,基类将以ASSERT 的形式抱怨uFlag 成员。 而且由于我们需要设置ID,所以我们还需要设置一个矩形。我创建了一个CRect 成员并在CTor 中将其设置为(0, 0, 10000, 10000)。我还没有找到改变工具矩形大小的工作方法,所以这是我非常丑陋的解决方法。这也是我将此解决方案称为部分解决方案的原因。 更新:I asked a question regarding this.

      终于有了获取工具提示信息的处理程序:

      // Message map entry
      ON_NOTIFY(TVN_GETINFOTIP, TREECTRL_ID, &CMobileCatalogPane::OnTvnGetInfoTip)
      
      
      // Handler
      void CMyPane::OnTvnGetInfoTip(NMHDR *pNMHDR, LRESULT *pResult)
      {
          LPNMTVGETINFOTIP pGetInfoTip = reinterpret_cast<LPNMTVGETINFOTIP>(pNMHDR);
      
          // This is a CString member
          m_toolTipText.ReleaseBuffer();
          m_toolTipText.Empty();
      
          // Set your text here...
      
          pGetInfoTip->pszText = m_toolTipText.GetBuffer();
      
          *pResult = 0;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-07
        • 2012-05-28
        • 1970-01-01
        • 1970-01-01
        • 2019-09-23
        • 1970-01-01
        相关资源
        最近更新 更多