Как отображать настраиваемые всплывающие подсказки в CTreeCtrl?

У меня есть класс, производный от 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. Может ли быть какая-то дополнительная работа, необходимая для этого, чтобы работать?


person foraidt    schedule 06.11.2008    source источник


Ответы (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() с меньшим количеством параметров, потому что базовый класс будет жаловаться в форме ASSERT на член uFlag, если идентификатор инструмента не установлен. А так как нам нужно установить ID, нам также нужно установить прямоугольник. Я создал член CRect и установил для него (0, 0, 10000, 10000) в CTor. Я еще не нашел рабочий способ изменить размер прямоугольника инструмента, так что это мой очень уродливый обходной путь. Вот почему я называю это решение частичным. Обновление: я задал вопрос по этому поводу.

Наконец, есть обработчик для получения всплывающей подсказки:

// 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;
}
person foraidt    schedule 15.05.2009

Я считаю, что вам все равно нужно включить всплывающую подсказку, даже если вы заменяете встроенный.

EnableToolTips(TRUE);

Ну, так как это не сработало для вас, и поскольку ни один эксперт не предложил никакой помощи, вот еще несколько предложений от меня. Хотя они хромают, они могут снова заставить вас двигаться:

  • Убедитесь, что ваша программа OnCreate() действительно выполняется.
  • Включите подсказку инструмента ПЕРЕД ее заменой.
  • Код, который я использую для этого, выглядит так. ( Признаюсь, я не понимаю всех деталей, я скопировал это из какого-то примера кода, это сработало, и поэтому я больше никогда не смотрел на это. )

    // Включить стандартную подсказку

    Включить всплывающие подсказки (ИСТИНА);

    // Отключаем встроенную подсказку

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

person ravenspoint    schedule 06.11.2008
comment
Кажется, это не имеет никакого эффекта. Я добавил это в код, хотя. Вместе с вызовом CToolTipCtrl::Activate(). - person foraidt; 07.11.2008
comment
Спасибо за обновления! К сожалению, дальше я ничего не понимаю... Я убедился, что OnCreate() вызывается, и включение подсказок перед заменой, похоже, не имеет никакого эффекта. Также нет вызова SendMessage(). Я считаю, что это только извлекает указатель и фактически ничего не отключает. - person foraidt; 07.11.2008
comment
Что ж, это позор. Странно, что никто не внес свой вклад. Я могу только предложить вам создать простейшее приложение для отображения всплывающей подсказки в тестовом дереве и посмотреть, работает ли оно. Кстати, Sendmessage() делает больше, чем извлекает указатель. - person ravenspoint; 07.11.2008

Я не пробовал в CTreeCtrl, но я думаю, что вы должны вызвать RelayEvent, чтобы ctrl всплывающей подсказки знал, когда должна отображаться всплывающая подсказка. Попробуй это:

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

Я надеюсь, что это поможет.

person Javier De Pedro    schedule 09.11.2008
comment
На форуме я прочитал, что нужно вызывать RelayEvent(), если элемент управления принадлежит диалогу. Однако в примере не упоминается вызов Activate(). Я попробовал ваше предложение, но все равно безуспешно... - person foraidt; 11.11.2008
comment
Мне жаль это слышать. Как я уже сказал, я не пробовал ни с CTreeCtrl, ни с CDockablePane. Может быть, если вы можете загрузить приложение, мы могли бы посмотреть. - person Javier De Pedro; 11.11.2008

Вам не нужно переопределять 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 пикселя, центрированный вокруг положения мыши. Элемент управления всплывающей подсказкой использует этот прямоугольник в качестве ограничивающего прямоугольника «инструмента», который я хочу сделать крошечным, поэтому перемещение мыши в любом месте будет означать перемещение за пределы инструмента. Я установил TTF _ NOTBUTTON в uFlags, потому что всплывающая подсказка не связана с кнопкой. Это специальный флаг MFC, определенный в afxwin.h; MFC использует его, чтобы помочь всплывающим подсказкам. Есть еще один расширенный MFC флаг для всплывающих подсказок, TTF _ ALWAYSTIP. Вы можете использовать его, если хотите, чтобы MFC отображала подсказку, даже когда ваше окно не активно. Вы, возможно, заметили, что до сих пор я не сообщал ни MFC, ни всплывающей подсказке, ни TOOLINFO настоящий текст подсказки. Вот для чего нужен LPSTR _ TEXTCALLBACK. Это специальное значение указывает элементу управления всплывающей подсказкой (внутреннему глобальному потоку, который использует MFC) вызвать мое окно обратно, чтобы получить текст. Он делает это, отправляя моему окну сообщение WM _ NOTIFY с кодом уведомления TTN _ NEEDTEXT.

person JeffH    schedule 28.04.2009
comment
Я не уверен, что я делаю неправильно, но я все еще не получаю уведомление TTN_NEEDTEXT... - person foraidt; 08.05.2009

Попробуйте специально обработать все идентификаторы всплывающих подсказок:

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

Если это не сработает, возможно, вам придется вручную вызвать RelayEvent() из PreTranslateMessage().

person skst    schedule 08.11.2008