Borbin the 🐱

CMFCRibbonBar: change tooltips at runtime

23 February, 2013


Tooltips gets displayed as the string part after the '\n' char of the matching resource. So in case you were wondering why you don't see tooltips in your new ribbon if you use your existing string IDs, add the newline to the string resource. But how to change tooltips of the MFC ribbon bar at runtime?
Using the OnToolTipNotify doesn't work with the MFC ribbon bar because no IDs are used.

But here is a trick to make it work:
Derive a new class from the CMFCRibbonBar class to override the TTN_NEEDTEXT message.

class CMyRibbonBar : public CMFCRibbonBar
{
protected:
    //{{AFX_MSG(CMyRibbonBar)
    afx_msg BOOL OnNeedTipText(UINT id, NMHDR* pNMH, LRESULT* pResult);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};


Set the TTN_NEEDTEXT message handler.

BEGIN_MESSAGE_MAP(CMyRibbonBar, CMFCRibbonBar)
    ON_NOTIFY_EX_RANGE(TTN_NEEDTEXT, 0, 0xFFFF, &CMyRibbonBar::OnNeedTipText)
END_MESSAGE_MAP()


The new TTN_NEEDTEXT message handler gets the original tooltip text, modify the text and sends back the new tooltip text. The MFC ribbon bar does not send the resource ID of the tool. Because of this, the tooltips are matched by string content.

BOOL CMyRibbonBar::OnNeedTipText(UINT id, NMHDR* pNMH, LRESULT* pResult)
{
    static CString strTipText;

    // get tooltip text
    BOOL ret = CMFCRibbonBar::OnNeedTipText(id, pNMH, pResult);

    LPNMTTDISPINFO pTTDispInfo = (LPNMTTDISPINFO)pNMH;
    strTipText = pTTDispInfo->lpszText;

    // modify tooltip text
    CString strRes;
    strRes.LoadString(ID_MY_UI_ELEMENT);
    strRes.TrimLeft(_T('\n'));

    if(strTipText == strRes)
    {
        // new content for ID_MY_UI_ELEMENT
        strTipText = "New tool tip content\r2nd Line";
        pTTDispInfo->lpszText = const_cast<LPTSTR>((LPCTSTR)strTipText);
    }

    return ret;
}


To set tooltip for the drop down menus, simply get the element via the ID, and use the SetToolTipText API. Here is an example on how it is done for the plugins menu in cPicture:

    // Add the tooltips.
    for (vector<FunctionPlugin>::const_iterator it = CRegisterFunctionPlugin::s_vec_function_plugin.begin(); it != CRegisterFunctionPlugin::s_vec_function_plugin.end(); ++it)
    {
        const UINT i(static_cast<UINT>(it - CRegisterFunctionPlugin::s_vec_function_plugin.begin()));

        CMFCRibbonBaseElement* pElement = FindByID(ID_FUNCTION_PLUGINS_START + i, FALSE, TRUE);
        if (pElement)
        {
            pElement->SetToolTipText(it->pluginData.desc);
        }
    }