В стандартном проекте C ++ / MFC MDI doc / view я хочу реализовать всплывающую подсказку отслеживания в представлении (окна представления с вкладками, которые обычно занимают большую часть окна основного фрейма). Итак, в классе MyAppView
У меня есть член CToolTipCtrl tooltip
, функция MyAppView::OnInitialUpdate()
содержит инициализацию
BOOL ok0 = tooltip.Create(this, TTS_ALWAYSTIP);
CRect clientRect; GetClientRect(&clientRect);
BOOL ok2 = tooltip.AddTool(this, LPSTR_TEXTCALLBACK, &clientRect, 1234/*tool ID*/);
tooltip.Activate(TRUE);
сделать всю клиентскую область представления «инструментом». Карта сообщений содержит запись
ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnNeedToolTipText)
и функция OnNeedToolTipText
определяется как
BOOL MyAppView::OnNeedToolTipText(UINT id, NMHDR *pNMHDR, LRESULT *pResult)
{
UNREFERENCED_PARAMETER(id);
NMTTDISPINFO *pTTT = (NMTTDISPINFO *)pNMHDR;
UINT_PTR nID = pNMHDR->idFrom;
BOOL bRet = FALSE;
if(nID == 1234)
{
// Come here when text is needed for tracking tooltip
}
if(pTTT->uFlags & TTF_IDISHWND)
{
// idFrom is actually the HWND of the tool
nID = ::GetDlgCtrlID((HWND)nID);
if(nID)
{
_stprintf_s(pTTT->szText, sizeof(pTTT->szText) / sizeof(TCHAR),
_T("Control ID = %d"), nID);
pTTT->hinst = AfxGetResourceHandle();
bRet = TRUE;
}
}
*pResult = 0;
return bRet;
}
То, что происходит, — то, что только размещение мыши на пунктах меню (Файл, Редактировать, Вид, Окно, Справка) приводит к вводу кода OnNeedToolTipText
с идентификатором 0-5. Перемещение мыши в клиентскую область (вид) ничего не делает.
Как заставить всплывающую подсказку появляться только в клиентской области представления?
Visual Studio 2017; C ++; 64-битная Windows 7
Для решения проблемы необходимо сделать следующее:
BOOL CMyAppView::PreTranslateMessage(MSG* pMsg)
{
switch (pMsg->message)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
case WM_MOUSEMOVE:
if (m_pToolTip->GetSafeHwnd () != NULL)
{
m_pToolTip->RelayEvent(pMsg);
}
break;
}
return CScrollView::PreTranslateMessage(pMsg);
}
Если вам нужна подсказка для отслеживания в представлении, выполните следующие действия:
Создайте подсказку и добавьте инструмент.
void CToolTipDemoView::OnInitialUpdate()
{
// ...
m_toolTip.Create(this, TTS_ALWAYSTIP | TTS_NOANIMATE);
m_toolTip.AddTool(this, _T("Doesn't matter"));
}
Обрабатывать сообщение WM_MOUSEMOVE. Сначала вызовите _TrackMouseEvent, чтобы в дальнейшем получить WM_MOUSELEAVE и активировать всплывающую подсказку. Во-вторых, обновите текст подсказки и покажите его в координатах указателя мыши.
void CToolTipDemoView::OnMouseMove(UINT nFlags, CPoint point)
{
if (!m_bTrackingMouseLeave)
{
TRACKMOUSEEVENT tme = { 0 };
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = m_hWnd;
::_TrackMouseEvent(&tme);
m_toolTip.Activate(TRUE);
m_bTrackingMouseLeave = TRUE;
}
if (m_pointLastMousePos != point)
{
CString strText;
strText.Format(_T("x = %d y = %d"), point.x, point.y);
m_toolTip.UpdateTipText(strText, this);
m_toolTip.Popup();
m_pointLastMousePos = point;
}
CScrollView::OnMouseMove(nFlags, point);
}
Обработайте WM_MOUSELEAVE и деактивируйте подсказку.
void CCToolTipDemoView::OnMouseLeave()
{
m_bTrackingMouseLeave = FALSE;
// mouse pointer leaves the window so deactivate the tooltip
m_toolTip.Activate(FALSE);
CScrollView::OnMouseLeave();
}
Заметки:
Поэтому я вернулся, чтобы посмотреть, чего мне не хватает. Я написал это более 10 лет назад. Я также переопределил член CWnd
virtual INT_PTR OnToolHitTest( CPoint point, TOOLINFO* pTI ) const;
С:
INT_PTR HERichView::OnToolHitTest( CPoint point, TOOLINFO* pTI ) const
{
pTI->hwnd = m_hWnd;
pTI->uId = point.x + ( point.y << 16 );
CRect rect;
GetClientRect( rect );
pTI->rect= rect;
pTI->lpszText= LPSTR_TEXTCALLBACK;
return pTI->uId;
}
И я проверил, без этого не получится. Так что ваши:
ON_NOTIFY_EX( TTN_NEEDTEXT, 0, OnToolTip )
Должен позвонить, если вы добавите выше. И только EnableToolTips( );
Должно быть необходимо.
Мне не удалось заставить всплывающую подсказку работать в MFC. Самое близкое, что я пришел, это
В карте сообщений: ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnNeedToolTipText)
В OnInitialUpdate
: BOOL ok1 = EnableTrackingToolTips(TRUE);
В переопределении виртуальной функции OnToolHitTest
:
pTI->hwnd = m_hWnd;
pTI->uId = (UINT_PTR)m_hWnd;
pTI->uFlags = TTF_IDISHWND | TTF_ALWAYSTIP | TTF_TRACK | TTF_NOTBUTTON | TTF_ABSOLUTE | TTF_SUBCLASS;
pTI->lpszText = LPSTR_TEXTCALLBACK;
return pTI->uId;
В OnNeedToolTipText
:
NMTTDISPINFO *pTTT = (NMTTDISPINFO *)pNMHDR;
UINT_PTR nID = pNMHDR->idFrom;
BOOL bRet = FALSE;
if(pTTT->uFlags & TTF_IDISHWND)
{
// idFrom is actually the HWND of the tool
nID = ::GetDlgCtrlID((HWND)nID);
if(nID)
{
CURSORINFO ci; ci.cbSize = sizeof(CURSORINFO); // get something interesting to display
GetCursorInfo(&ci);
_stprintf_s(pTTT->szText, sizeof(pTTT->szText) / sizeof(TCHAR),
_T("Control ID = %lld at (%d, %d)"), nID, ci.ptScreenPos.x, ci.ptScreenPos.y);
pTTT->hinst = AfxGetResourceHandle();
bRet = TRUE;
}
}
*pResult = 0;
return bRet;
Это производит следующее своеобразное поведение. Когда я запускаю приложение и перемещаю курсор мыши в клиентскую область CScrollView, рядом с курсором появляется всплывающая подсказка.
Если я аккуратно (плавно) перемещаю мышь, подсказка отслеживается правильно. Однако через некоторое время он исчезает, и никакие дальнейшие движения мыши, в том числе выход из окна CScrollView и возвращение, не вызывают его повторное появление.
Я думаю, что происходит, когда курсор мыши перемещается над окном подсказки, подсказка отключается навсегда. Это исчезновение, похоже, не связано со временем (например, из-за автоматического всплытия); если мышь оставить нетронутой, всплывающая подсказка останется на неопределенный срок.