如何在 CTreeCtrl 中显示自定义工具提示?

发布于 2024-07-09 11:35:17 字数 1011 浏览 17 评论 0原文

我有一个从 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。 是否需要做一些额外的工作才能实现这一点?

I have a class derived from CTreeCtrl. In OnCreate() I replace the default CToolTipCtrl object with a custom one:

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

My message handler looks like this:

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

However I never receive a TTN_NEEDTEXT message. I had a look with Spy++ and it also looks like this message never gets sent.

What could be the problem here?

Update

I'm not sure whether this is relevant: The CTreeCtrl's parent window is of type CDockablePane. Could there be some extra work needed for this to work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

喜你已久 2024-07-16 11:35:17

最后! 我(部分)解决了它:

看起来 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)。 我还没有找到改变工具矩形大小的工作方法,所以这是我非常丑陋的解决方法。 这也是我将此解决方案称为部分解决方案的原因。 更新:我问了一个与此相关的问题。

最后是获取工具提示信息的处理程序:

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

Finally! I (partially) solved it:

It looks like the CDockablePane parent window indeed caused this problem...

First I removed all the tooltip-specific code from the CTreeCtrl-derived class. Everything is done in the parent pane window.

Then I edited the parent window's OnCreate() method:

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;

}

Unforunately we cannot simply call AddTool() with less parameters because the base class will complain in the form of an ASSERT about a uFlag member if there is no tool ID set.
And since we need to set the ID, we also need to set a rectangle. I created a CRect member and set it to (0, 0, 10000, 10000) in the CTor. I have not yet found a working way to change the tool's rect size so this is my very ugly workaround. This is also why I call this solution partial. Update: I asked a question regarding this.

Finally there is the handler to get the tooltip info:

// 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;
}
平定天下 2024-07-16 11:35:17

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

EnableToolTips(TRUE);

好吧,既然这对你不起作用,而且没有更多的专家提供任何帮助,这里还有我的一些建议。 尽管它们很蹩脚,但它们可能会让您再次前进:

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

    // 启用标准工具提示

    启用工具提示(TRUE);

    // 禁用内置工具提示

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

I believe you still have to enable the tooltip, even though you are replacing the builtin.

EnableToolTips(TRUE);

Well, since that did not work for you and since no-one more expert has offered any help, here a few more suggestions from me. Although they are lame, they might get you moving again:

  • Make sure your OnCreate() rotine is actually being executed.
  • Enable the tool tip BEFORE you replace it.
  • The code I use to do this looks like this. ( I confess I do not understand all the details, I copied it from some sample code, it worked and so I never looked at it any more. )

    // Enable the standard tooltip

    EnableToolTips(TRUE);

    // Disable the builtin tooltip

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

另类 2024-07-16 11:35:17

我还没有在 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);
}

我希望这有帮助。

I haven't tried in a CTreeCtrl but I think you should call RelayEvent for the tooltip ctrl to know when the tooltip has to be displayed. Try this:

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

I hope this help.

神也荒唐 2024-07-16 11:35:17

你不需要重写OnToolHitTest()吗?

(旧)资源 1

(旧)资源 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 消息来实现此目的。

Don't you have to override OnToolHitTest()?

(old) Resource 1

(old) Resource 2:

In addition to returning the hit code (nHit), you also have to fill out the TOOLINFO struct. Here's how VIRGIL does it in 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;

Most of this is obvious—like setting hwnd and uId—but some of it is less so. I set the rect member to a 2-pixel-wide, 2-pixel-high rectangle centered around the mouse location. The tooltip control uses this rectangle as the bounding rectangle of the "tool," which I want to be tiny, so moving the mouse anywhere will constitute moving outside the tool. I set TTF _ NOTBUTTON in uFlags because the tooltip is not associated with a button. This is a special MFC flag defined in afxwin.h; MFC uses it to do help for tooltips. There's another MFC-extended flag for tooltips, TTF _ ALWAYSTIP. You can use it if you want MFC to display the tip even when your window is not active.
You may have noticed that so far I haven't told MFC or the tooltip or the TOOLINFO what the actual text of the tip is. That's what LPSTR _ TEXTCALLBACK is for. This special value tells the tooltip control (the internal, thread-global one that MFC uses) to call my window back to get the text. It does this by sending my window a WM _ NOTIFY message with notification code TTN _ NEEDTEXT.

烟柳画桥 2024-07-16 11:35:17

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

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

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

Try to specifically handle all tooltip ids:

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

If that doesn't work, you may have to manually call RelayEvent() from PreTranslateMessage().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文