Читать «Исчерпывающее руководство по написанию всплывающих подсказок» онлайн - страница 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 подставляется максимум от ширины строки и вычисленной ширины строки (плюс немного места по краям из эстетических соображений).