ΠΠ»Π°ΡΡ 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 ΠΏΠΎΠ΄ΡΡΠ°Π²Π»ΡΠ΅ΡΡΡ ΠΌΠ°ΠΊΡΠΈΠΌΡΠΌ ΠΎΡ ΡΠΈΡΠΈΠ½Ρ ΡΡΡΠΎΠΊΠΈ ΠΈ Π²ΡΡΠΈΡΠ»Π΅Π½Π½ΠΎΠΉ ΡΠΈΡΠΈΠ½Ρ ΡΡΡΠΎΠΊΠΈ (ΠΏΠ»ΡΡ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΌΠ΅ΡΡΠ° ΠΏΠΎ ΠΊΡΠ°ΡΠΌ ΠΈΠ· ΡΡΡΠ΅ΡΠΈΡΠ΅ΡΠΊΠΈΡ ΡΠΎΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠΉ).