Search code examples
c++mfctooltipmfc-feature-pack

How do I display custom tooltips in a CTreeCtrl?


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?


Solution

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