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

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

Рис.11. CTitleTip

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

>// CTitleTip window

>class CTitleTip : public CWnd {

>public:

> CTitleTip();

> virtual BOOL Create(CListBox* pParentWnd);

> virtual void Show(CRect DisplayRect, int nItemIndex);

> virtual void Hide();

>// Overrides

> // ClassWizard generated virtual function overrides

> //{{AFX_VIRTUAL(CTitleTip)

> //}}AFX_VIRTUAL

> // Implementation

>public:

> virtual ~CTitleTip();

>protected:

> const int m_nNoIndex; // Пустой индекс

> static LPCSTR m_pszWndClass; // Имя зарегистрированного класса

> int m_nItemIndex; // Индекс строки, для которой показывается подсказка

> CListBox* m_pListBox; // Родительское окно

> BOOL IsListBoxOwnerDraw();

> // Generated message map functions

>protected:

> //{{AFX_MSG(CTitleTip)

> afx_msg void OnPaint();

> //}}AFX_MSG

> DECLARE_MESSAGE_MAP()

>};


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

>// TitleTip.cpp : implementation file //

>#include "stdafx.h"

>#include "TitleTip.h"


>#ifdef _DEBUG

>#define new DEBUG_NEW

>#undef THIS_FILE

>static char THIS_FILE[] = __FILE__;

>#endif


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

>// CTitleTip

>LPCSTR CTitleTip::m_pszWndClass = NULL;

>CTitleTip::CTitleTip() : m_nNoIndex(-1) {

> // Зарегистрировать класс окна, если он еще не зарегистрирован

> // другим экземпляром CTitleTip.

> if (m_pszWndClass == NULL) {

>  m_pszWndClass = AfxRegisterWndClass(CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW);

> }

> m_nItemIndex = m_nNoIndex;

> m_pListBox = NULL;

>}


>CTitleTip::~CTitleTip() { }


>BOOL CTitleTip::Create(CListBox* pParentWnd) {

> ASSERT_VALID(pParentWnd);

> m_pListBox = pParentWnd;

> // Не рисовать рамку для обычных элементов "список", так как

> // строки с пользовательской отрисовкой добавляют рамку автоматически.

> DWORD dwStyle = WS_POPUP;

> if (!IsListBoxOwnerDraw()) {

>  dwStyle |= WS_BORDER;

> }

> return CreateEx(0, m_pszWndClass, NULL, dwStyle, 0, 0, 0, 0, pParentWnd->GetSafeHwnd(), NULL, NULL);

>}


>BOOL CTitleTip::IsListBoxOwnerDraw() {

> ASSERT_VALID(m_pListBox);

> DWORD dwStyle = m_pListBox->GetStyle();

> return (dwStyle & LBS_OWNERDRAWFIXED) || (dwStyle & LBS_OWNERDRAWVARIABLE);

>}


>void CTitleTip::Show(CRect DisplayRect, int nItemIndex) {

> ASSERT_VALID(m_pListBox);

> ASSERT(nItemIndex < m_pListBox->GetCount());

> ASSERT(nItemIndex >= 0);

> ASSERT(::IsWindow(m_hWnd));

> ASSERT(!DisplayRect.IsRectEmpty());

> // Пометить для обновления, если новая строка.

> if (m_nItemIndex != nItemIndex) {

>  m_nItemIndex = nItemIndex;

>  InvalidateRect(NULL);

> }

> // Установить позицию и видимость окна.

> CRect WindowRect;

> GetWindowRect(WindowRect);

> int nSWPFlags = SWP_SHOWWINDOW | SWP_NOACTIVATE;

> if (WindowRect == DisplayRect) {

>  nSWPFlags |= SWP_NOMOVE | SWP_NOSIZE;

> }

> VERIFY(SetWindowPos(&wndTopMost, DisplayRect.left, DisplayRect.top, DisplayRect.Width(), DisplayRect.Height(), nSWPFlags));

>}


>void CTitleTip::Hide() {

> ASSERT(::IsWindow(m_hWnd));

> ShowWindow(SW_HIDE);

>}


>BEGIN_MESSAGE_MAP(CTitleTip, CWnd)

> //{{AFX_MSG_MAP(CTitleTip)

> ON_WM_PAINT()

> //}}AFX_MSG_MAP

>END_MESSAGE_MAP()


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

>// CTitleTip message handlers

>void CTitleTip::OnPaint() {

> ASSERT(m_nItemIndex != m_nNoIndex);

> CPaintDC DC(this);

> int nSavedDC = DC.SaveDC();

> CRect ClientRect;

> GetClientRect(ClientRect);

> if (IsListBoxOwnerDraw()) {

>  // Доверим рисование элементу "список".

>  DRAWITEMSTRUCT DrawItemStruct;

>  DrawItemStruct.CtlType = ODT_LISTBOX;

>  DrawItemStruct.CtlID = m_pListBox->GetDlgCtrlID();

>  DrawItemStruct.itemID = m_nItemIndex;

>  DrawItemStruct.itemAction = ODA_DRAWENTIRE;

>  DrawItemStruct.hwndItem = m_pListBox->GetSafeHwnd();

>  DrawItemStruct.hDC = DC.GetSafeHdc();

>  DrawItemStruct.rcItem = ClientRect;

>  DrawItemStruct.itemData = m_pListBox->GetItemData(m_nItemIndex);

>  DrawItemStruct.itemState = (m_pListBox->GetSel(m_nItemIndex) > 0 ? ODS_SELECTED : 0);

>  if (m_pListBox->GetStyle() & LBS_MULTIPLESEL) {

>   if (m_pListBox->GetCaretIndex() == m_nItemIndex) {

>    DrawItemStruct.itemState |= ODS_FOCUS;

>   }

>  } else {

>   DrawItemStruct.itemState |= ODS_FOCUS;

>  }

>  m_pListBox->DrawItem(&DrawItemStruct);

> } else {

>  // Рисуем самостоятельно

>  CFont* pFont = m_pListBox->GetFont();

>  ASSERT_VALID(pFont);

>  DC.SelectObject(pFont);

>  COLORREF clrBackground = RGB(255, 255, 255);

>  if (m_pListBox->GetSel(m_nItemIndex) > 0) {

>   DC.SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));

>   clrBackground = ::GetSysColor(COLOR_HIGHLIGHT);

>  }

>  // Рисуем фон

>  DC.FillSolidRect(ClientRect, clrBackground);

>  // Рисуем текст строки

>  CString strItem;

>  m_pListBox->GetText(m_nItemIndex, strItem);

>  ASSERT(!strItem.IsEmpty());

>  DC.SetBkMode(TRANSPARENT);

>  DC.TextOut(1, –1, strItem);

> }

> DC.RestoreDC(nSavedDC);

> // Не вызываем CWnd::OnPaint() для сообщений отрисовки

>}

CTitleTip::CTitleTip регистрирует класс окна вызовом функции AfxRegisterWndClass и сохраняет имя класса в переменной CTitleTip::m_pszWndClass. Я использую функцию AfxRegisterWndClass, чтобы иметь возможность зарегистрировать класс окна с установленным стилем CS_SAVEBITS. Флаг CS_SAVEBITS используется для оптимизации – Windows сохраняет кусок окна, заслоненного элементом TitleTip, как картинку. В результате, этому окну не нужно посылать сообщение WM_PAINT, когда подсказка убирается с экрана. CTitleTip::Create создает подсказку в виде popup-окна. К окну подсказки рамка добавляется только если элемент "список" является обычным, так как Windows автоматически добавляет рамку к элементам "список" с пользовательской отрисовкой перед посылкой сообщения WM_DRAWITEM. Обратите внимание, что значение переменной CTitleTip::m_pszWndClass передается в качестве имени класса окна в функцию CWnd::CreateEx. CTitleTip::IsListBoxOwnerDraw возвращает TRUE, если родительский элемент "список" является элементом с пользовательской отрисовкой. Функция узнает об этом по стилю элемента "список".


Рекомендуем почитать
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 так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.