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

时间:2008-11-06 18:47:41

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

我有一个派生自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类型。这需要一些额外的工作吗?

5 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:4)

我相信你仍然需要启用工具提示,即使你要更换内置。

EnableToolTips(TRUE);

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

  • 确保您的OnCreate()实际上正在执行。
  • 在更换之前启用工具提示。
  • 我用来做这个的代码看起来像这样。 (我承认我不了解所有细节,我从一些示例代码复制它,它工作,所以我再也没有看过它了。)

    //启用标准工具提示

    EnableToolTips(TRUE);

    //禁用内置工具提示

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

答案 2 :(得分:1)

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

我希望这有帮助。

答案 3 :(得分:1)

您是否必须覆盖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消息来完成此操作。

答案 4 :(得分:0)

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

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

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