Исчерпывающее руководство по написанию всплывающих подсказок - [10]

Шрифт
Интервал

> DWORD dwStyle = GetStyle();

> int nStatus = GetItemRect(nIndex, lpRect);

> if (nStatus != LB_ERR && !(dwStyle & LBS_OWNERDRAWFIXED) && !(dwStyle & LBS_OWNERDRAWVARIABLE)) {

>  CString strItem;

>  GetText(nIndex, strItem);

>  if (!strItem.IsEmpty()) {

>   // Вычислить длину идеального текста.

>   CClientDC DC(this);

>   CFont* pOldFont = DC.SelectObject(GetFont());

>   CSize ItemSize = DC.GetTextExtent(strItem);

>   DC.SelectObject(pOldFont);

>   // Взять максимум от обычной ширины и идеальной ширины.

>   const int cxEdgeSpace = 2;

>   lpRect->right = max(lpRect->right, lpRect->left + ItemSize.cx + (cxEdgeSpace * 2));

>  }

> } else {

>  TRACE("Owner-draw listbox detected – override CTitleTipListBox::GetIdeaItemRect()\n");

> }

> return nStatus;

>}


>void CTitleTipListBox::AdjustTitleTip(int nNewIndex) {

> if (!::IsWindow(m_TitleTip.m_hWnd)) {

>  VERIFY(m_TitleTip.Create(this));

> }

> if (nNewIndex == m_nNoIndex) {

>  m_TitleTip.Hide();

> } else {

>  CRect IdealItemRect;

>  GetIdealItemRect(nNewIndex, IdealItemRect);

>  CRect ItemRect;

>  GetItemRect(nNewIndex, ItemRect);

>  if (ItemRect == IdealItemRect) {

>   m_TitleTip.Hide();

>  } else {

>   // Поправить координаты рядом с краем экрана.

>   ClientToScreen(IdealItemRect);

>   int nScreenWidth = ::GetSystemMetrics(SM_CXFULLSCREEN);

>   if (IdealItemRect.right > nScreenWidth) {

>    IdealItemRect.OffsetRect(nScreenWidth – IdealItemRect.right, 0);

>   }

>   if (IdealItemRect.left < 0) {

>    IdealItemRect.OffsetRect(-IdealItemRect.left, 0);

>   }

>   m_TitleTip.Show(IdealItemRect, nNewIndex);

>  }

> }

> if (m_TitleTip.IsWindowVisible()) {

>  // Удостовериться, что мышь захвачена, чтобы отследить

>  // момент отключения подсказки.

>  if (!m_bMouseCaptured && GetCapture() != this) {

>   CaptureMouse();

>  }

> } else {

>  // Подсказка невидима, поэтому освободить мышь.

>  if (m_bMouseCaptured) {

>   VERIFY(ReleaseCapture());

>   m_bMouseCaptured = FALSE;

>  }

> }

>}


>void CTitleTipListBox::CaptureMouse() {

> ASSERT(!m_bMouseCaptured);

> CPoint Point;

> VERIFY(GetCursorPos(&Point));

> ScreenToClient(&Point);

> m_LastMouseMovePoint = Point;

> SetCapture();

> m_bMouseCaptured = TRUE;

>}


>/////////////////////////////////////////////////////////////////////////////

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


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


MFC и OpenGL

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Симуляция частичной специализации

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Обработка событий в С++

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.