Читать «Исчерпывающее руководство по написанию всплывающих подсказок» онлайн - страница 18
Роджер Джек
// CTitleTipListBox message handlers
LONG CTitleTipListBox::OnContentChanged(UINT, LONG) {
// Turn off title tip.
AdjustTitleTip(m_nNoIndex);
return Default();
}
void CTitleTipListBox::OnMouseMove(UINT nFlags, CPoint point) {
if (point != m_LastMouseMovePoint && IsAppActive()) {
m_LastMouseMovePoint = point;
int nIndexHit = m_nNoIndex;
CRect ClientRect;
GetClientRect(ClientRect);
if (ClientRect.PtInRect(point)) {
// Hit test.
for (int n = 0; nIndexHit == m_nNoIndex && n < GetCount(); n++) {
CRect ItemRect;
GetItemRect(n, ItemRect);
if (ItemRect.PtInRect(point)) {
nIndexHit = n;
}
}
}
AdjustTitleTip(nIndexHit);
}
CListBox::OnMouseMove(nFlags, point);
}
void CTitleTipListBox::OnSelchange() {
int nSelIndex;
if (GetStyle() & LBS_MULTIPLESEL) {
nSelIndex = GetCaretIndex();
} else {
nSelIndex = GetCurSel();
}
AdjustTitleTip(nSelIndex);
m_TitleTip.InvalidateRect(NULL);
m_TitleTip.UpdateWindow();
}
void CTitleTipListBox::OnKillFocus(CWnd* pNewWnd) {
CListBox::OnKillFocus(pNewWnd);
if (pNewWnd != &m_TitleTip) {
AdjustTitleTip(m_nNoIndex);
}
}
void CTitleTipListBox::OnDestroy() {
AdjustTitleTip(m_nNoIndex);
m_TitleTip.DestroyWindow();
CListBox::OnDestroy();
}
void CTitleTipListBox::OnLButtonDown(UINT nFlags, CPoint point) {
// Временно отключить захват мыши, так как базовый класс может
// захватить мышь.
if (m_bMouseCaptured) {
ReleaseCapture();
m_bMouseCaptured = FALSE;
}
CListBox::OnLButtonDown(nFlags, point);
if (m_TitleTip.IsWindowVisible()) {
m_TitleTip.InvalidateRect(NULL);
if (this != GetCapture()) {
CaptureMouse();
}
}
}
void CTitleTipListBox::OnLButtonUp(UINT nFlags, CPoint point) {
CListBox::OnLButtonUp(nFlags, point);
if (this != GetCapture() && m_TitleTip.IsWindowVisible()) {
CaptureMouse();
}
}
BOOL CTitleTipListBox::PreTranslateMessage(MSG* pMsg) {
switch (pMsg->message) {
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
// Активизировать окно представления, потому что такое
// поведение подразумевается по сообщению WM_MOUSEACTIVATE,
// когда над окном нет никаких подсказок.
AdjustTitleTip(m_nNoIndex);
CFrameWnd* pFrameWnd = GetParentFrame();
if (pFrameWnd) {
BOOL bDone = FALSE;
CWnd* pWnd = this;
while (!bDone) {
pWnd = pWnd->GetParent();
if (!pWnd || pWnd == pFrameWnd) {
bDone = TRUE;
}
else if (pWnd->IsKindOf(RUNTIME_CLASS(CView))) {
pFrameWnd->SetActiveView((CView*)pWnd);
bDone = TRUE;
}
}
}
break;
}
return CListBox::PreTranslateMessage(pMsg);
}
Функция CTitleTipListBox::GetIdealItemRect вычисляет размер и координаты идеальной строки списка. Параметр nIndex – это индекс нужной строки. Параметр lpRect используется для того, чтобы вернуть идеальный размер и координаты в клиентской системе координат. Вы должны переопределить этот метод для элемента "список" с пользовательской отрисовкой, и далее я покажу, как с этим справляется CODListBox. Если не переопределить этот метод для элемента "список" с пользовательской отрисовкой, то метод CTitleTipListBox::GetIdealItemRect выдаст TRACE-сообщение об ошибке. Однако для обычных элементов "список" этот метод автоматически вычисляет размер и координаты идеальной строки списка. Сначала он вызывает функцию CListBox::GetItemRect для вычисления высоты и ширины строки. Ширина строки, возвращенная CListBox::GetItemRect является шириной самого элемента "список", а не шириной текста. Чтобы вычислить настоящую ширину текста подсказки, я получаю текст и шрифт для строки и вызываю CDC::GetTextExtent. Затем в lpRect подставляется максимум от ширины строки и вычисленной ширины строки (плюс немного места по краям из эстетических соображений).