Исчерпывающее руководство по написанию всплывающих подсказок | страница 16
>  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, если родительский элемент "список" является элементом с пользовательской отрисовкой. Функция узнает об этом по стилю элемента "список".