1
votes

For some reasons I have a parent window. This window contains normal controls. But it also takes child controls that again have controls in it. The real application is more complex. In the real version I also use WS_EX_CONTROLPARENT to allow navigation in the dialog between the nested controls.

For simplicity I created a dialog base application. In there is a normal edit control and a static control with an edit control in it. I just created the edit control inside my code.

I enabled the tool tips. In the normal way. Tooltips are shown for the buttons and the normal edit control. But the control inside the static doesn't show a tooltip.

How to get the tools tips for the nested controls too inside my handler?

Here the code for the CPP.

// ToolTipTestDlg.cpp : implementation file
#include "pch.h"
#include "framework.h"
#include "ToolTipTest.h"
#include "ToolTipTestDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CToolTipTestDlg dialog

CToolTipTestDlg::CToolTipTestDlg(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_TOOLTIPTEST_DIALOG, pParent)
{
    EnableToolTips();
}

void CToolTipTestDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_CONTAINER, m_container);
}

BEGIN_MESSAGE_MAP(CToolTipTestDlg, CDialogEx)
    ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
END_MESSAGE_MAP()

// CToolTipTestDlg message handlers

BOOL CToolTipTestDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    m_edit1.Create(WS_CHILD | WS_BORDER | WS_VISIBLE, CRect(10, 10, 110, 30), this, 1);
    m_edit2.Create(WS_CHILD | WS_BORDER | WS_VISIBLE, CRect(10, 10, 110, 30), &m_container, 1);

    return TRUE;  // return TRUE  unless you set the focus to a control
}

BOOL CToolTipTestDlg::OnToolTipText(UINT nId, NMHDR* pNMHDR, LRESULT* pResult)
{
    // For all keyboard messages we need to know the target of the message
    ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);
    TOOLTIPTEXTW* pTTTW = reinterpret_cast<NMTTDISPINFO*>(pNMHDR);

    CString strTipText = _T("Test");
    wcsncpy_s(pTTTW->szText, _countof(pTTTW->szText), CT2W(strTipText), _countof(pTTTW->szText));

    *pResult = 0;
    return TRUE;    // message was handled
}

The header file:

// ToolTipTestDlg.h : header file

#pragma once

// CToolTipTestDlg dialog
class CToolTipTestDlg : public CDialogEx
{
// Construction
public:
    CToolTipTestDlg(CWnd* pParent = nullptr);   // standard constructor

// Dialog Data
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_TOOLTIPTEST_DIALOG };
#endif

    CEdit m_edit1, m_edit2;
    CStatic m_container;

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
    // Generated message map functions
    virtual BOOL OnInitDialog();
    DECLARE_MESSAGE_MAP()
    afx_msg BOOL OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult);
};

And the RC file with the container:

/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_TOOLTIPTEST_DIALOG DIALOGEX 0, 0, 321, 96
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
    DEFPUSHBUTTON   "OK",IDOK,79,75,50,14
    PUSHBUTTON      "Cancel",IDCANCEL,134,75,50,14
    LTEXT           " ",IDC_CONTAINER,7,39,168,25,SS_NOTIFY
END
1
Would you have to possibly trigger it to display the tips? If the mouse is in the static control area fire something to trigger the tooltip stuff in your control? Just a guess as I don't really know!Andrew Truckle
I can see that the TTN_NEEDTEXT arrives. But the tooltip never shows up.xMRi

1 Answers

2
votes

My investigation showed that this MFC tooltip implementation is only designed for controls that are direct children for the control that called EnabledToolTips.

I found an solution that works. It may not be the best but it is easy to implement.

I use an own container class (in my real world code this class already exists)

class CStaticContainer : public CStatic
{

public:
DECLARE_MESSAGE_MAP()
    afx_msg BOOL OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult);
};

I made sure that this container class is used and subclassed the existing CStatic (here the code for the sample in the dialog class):

// In the dialog class 
CStaticContainer m_container;

...
void CToolTipTestDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_CONTAINER, m_container);
}

I enabled tooltips for the container too in OnInitDialog.

m_container.EnableToolTips();

For the container class I added a TTN_NEEDTEXT handler. It just forwards the message to the outer parent.

BEGIN_MESSAGE_MAP(CStaticContainer, CStatic)
    ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
END_MESSAGE_MAP()

BOOL CStaticContainer::OnToolTipText(UINT nId, NMHDR* pNMHDR, LRESULT* pResult)
{
    GetParent()->SendMessage(WM_NOTIFY, nId, reinterpret_cast<LPARAM>(pNMHDR));
    return TRUE;    // message was handled
}

Now the tool tips show up for all controls.