Π§ΠΈΡ‚Π°ΠΉΡ‚Π΅ ΠΊΠ½ΠΈΠ³ΠΈ ΠΎΠ½Π»Π°ΠΉΠ½ Π½Π° Bookidrom.ru! БСсплатныС ΠΊΠ½ΠΈΠ³ΠΈ Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΊΠ»ΠΈΠΊΠ΅

Π§ΠΈΡ‚Π°Ρ‚ΡŒ ΠΎΠ½Π»Π°ΠΉΠ½ Β«Π˜ΡΡ‡Π΅Ρ€ΠΏΡ‹Π²Π°ΡŽΡ‰Π΅Π΅ руководство ΠΏΠΎ написанию Π²ΡΠΏΠ»Ρ‹Π²Π°ΡŽΡ‰ΠΈΡ… подсказок». Π‘Ρ‚Ρ€Π°Π½ΠΈΡ†Π° 6

Автор Π ΠΎΠ΄ΠΆΠ΅Ρ€ Π”ΠΆΠ΅ΠΊ

Класс CTitleTipListBox ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ Π·Π° ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ элСмСнтом TitleTip (см. рис.12). Π’ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ CTitleTipListBox::m_LastMouseMovePoint хранится послСдняя позиция курсора ΠΌΡ‹ΡˆΠΈ. CTitleTipListBox::m_bMouseCaptured ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚, производится Π»ΠΈ Π² Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π·Π°Ρ…Π²Π°Ρ‚ ΠΌΡ‹ΡˆΠΈ (mouse capture). CTitleTipListBox::m_TitleTip – это экзСмпляр класса CTitleTip, ΡƒΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‰ΠΈΠΉ Π½Π° ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌΡƒΡŽ подсказку. CTitleTipListBox::m_nNoIndex – это константа, ΠΎΠ·Π½Π°Ρ‡Π°ΡŽΡ‰Π°Ρ, Ρ‡Ρ‚ΠΎ Π² элСмСнтС "список" Π½Π΅ отобраТаСтся подсказка Π½ΠΈ для ΠΎΠ΄Π½ΠΎΠΉ строки.

Рис.12. CTitleTipListBox

// TitleTipListBox.h : header file

//

/////////////////////////////////////////////////////////////////////////////

// CTitleTipListBox window

#ifndef __TITLETIPLISTBOX_H__

#define __TITLETIPLISTBOX_H__

#include "TitleTip.h"


class CTitleTipListBox : public CListBox { // Construction public:

 CTitleTipListBox();

// Overrides

 // ClassWizard generated virtual function overrides

 //{{AFX_VIRTUAL(CTitleTipListBox)

public:

 virtual BOOL PreTranslateMessage(MSG* pMsg);

 //}}AFX_VIRTUAL

 // Implementation

public:

 virtual ~CTitleTipListBox();

protected:

 const int m_nNoIndex; // ΠŸΡƒΡΡ‚ΠΎΠΉ индСкс

 CPoint m_LastMouseMovePoint; // ПослСдниС ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρ‹ курсора ΠΌΡ‹ΡˆΠΈ

 BOOL m_bMouseCaptured; // Π—Π°Ρ…Π²Π°Ρ‡Π΅Π½Π° Π»ΠΈ ΠΌΡ‹ΡˆΡŒ?

 CTitleTip m_TitleTip; // ΠŸΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌΡ‹ΠΉ элСмСнт TitleTip

 // Π­Ρ‚ΠΎΡ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ элСмСнтом "список" с ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠΉ отрисовкой.

 virtual int GetIdealItemRect(int nIndex, LPRECT lpRect);

 void AdjustTitleTip(int nNewIndex);

 void CaptureMouse();

 BOOL IsAppActive();

 // Generated message map functions

protected:

 //{{AFX_MSG(CTitleTipListBox)

 afx_msg void OnMouseMove(UINT nFlags, CPoint point);

 afx_msg void OnSelchange();

 afx_msg void OnKillFocus(CWnd* pNewWnd);

 afx_msg void OnDestroy();

 afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

 afx_msg void OnLButtonUp(UINT nFlags, CPoint point);

 //}}AFX_MSG

 afx_msg LONG OnContentChanged(UINT, LONG);

 DECLARE_MESSAGE_MAP()

};

#endif // __TITLETIPLISTBOX_H__


/////////////////////////////////////////////////////////////////////////////

// TitleTipListBox.cpp : implementation file

//

#include "stdafx.h"

#include "TitleTipListBox.h"


#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE static char THIS_FILE[] = __FILE__;

#endif


/////////////////////////////////////////////////////////////////////////////

// CTitleTipListBox

CTitleTipListBox::CTitleTipListBox() : m_LastMouseMovePoint(0, 0) , m_nNoIndex(-1) {

 m_bMouseCaptured = FALSE;

}


CTitleTipListBox::~CTitleTipListBox() {

 ASSERT(!m_bMouseCaptured);

}


int CTitleTipListBox::GetIdealItemRect(int nIndex, LPRECT lpRect) {

 // Π’Ρ‹Ρ‡ΠΈΡΠ»ΠΈΡ‚ΡŒ Ρ€Π°Π·ΠΌΠ΅Ρ€Ρ‹ идСальной строки. Π Π°Π·ΠΌΠ΅Ρ€Ρ‹ зависят

 // ΠΎΡ‚ Π΄Π»ΠΈΠ½Ρ‹ строки. Π­Ρ‚ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹Ρ… элСмСнтов

 // "список"(Π±Π΅Π· ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠΉ отрисовки)

 ASSERT(lpRect);

 ASSERT(nIndex >= 0);

 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 подставляСтся максимум ΠΎΡ‚ ΡˆΠΈΡ€ΠΈΠ½Ρ‹ строки ΠΈ вычислСнной ΡˆΠΈΡ€ΠΈΠ½Ρ‹ строки (плюс Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ мСста ΠΏΠΎ краям ΠΈΠ· эстСтичСских сообраТСний).