Figure 1 CWnd Support for ToolTips
| Member |
Description |
| BOOL EnableToolTips(BOOL bEnable) |
Enables or disables ToolTips for a window |
| virtual int CWnd::OnToolHitTest(CPoint point, TOOLINFO* pTI ) const |
Called by the framework to determine if the cursor is over a tool that has a ToolTip |
| void FilterToolTipMessage(MSG* pMsg) |
Checks to see if a message is relevant for displaying ToolTips |
| static void PASCAL CancelToolTips(BOOL bKeys) |
Hides a ToolTip if one is currently displayed |
Figure 4 HTML for a ToolTip
ASP File:
<OBJECT ID="WebButton1" WIDTH=31 HEIGHT=28
CLASSID="CLSID:381C5023-2FDA-11D0-8BC1-444553540000">
<PARAM NAME="_Version" VALUE="65536">
<PARAM NAME="_ExtentX" VALUE="786">
<PARAM NAME="_ExtentY" VALUE="731">
<PARAM NAME="_StockProps" VALUE="0">
<PARAM NAME="ToolTipText" VALUE="WebButton ToolTip Test">
</OBJECT>
</P>
<br><img src="Image.gif" height=48 width=48 alt="Image ToolTip" >
<SCRIPT LANGUAGE="VBScript">
<!--
Sub WebButton1_Click()
MsgBox "WebButton was clicked"
end sub
-->
</SCRIPT>
Figure 5 CWebButtonCtrl
// WebButtonCtl.cpp : Implementation of the CWebButtonCtrl OLE control class.
?
?
?
/////////////////////////////////////////////////////////////////////////////
// CWebButtonCtrl::RelayToolTipEvent - Pass mouse messages to ToolTip
void CWebButtonCtrl::RelayToolTipEvent(const MSG* pMsg)
{
MSG MsgCopy;
::memcpy(&MsgCopy, pMsg, sizeof(MSG));
FilterToolTipMessage(&MsgCopy);
}
int CWebButtonCtrl::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
{
if (m_bToolTipEnabled && pTI != NULL && pTI->cbSize >= sizeof(TOOLINFO))
{
// setup the TOOLINFO structure
pTI->hwnd = m_hWnd;
pTI->uId = 0;
pTI->uFlags = 0;
GetClientRect(&(pTI->rect));
pTI->lpszText = LPSTR_TEXTCALLBACK;
}
return (m_bToolTipEnabled ? 1 : -1);
}
/////////////////////////////////////////////////////////////////////////////
// CWebButtonCtrl message handlers
int CWebButtonCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (COleControl::OnCreate(lpCreateStruct) == -1)
{
return -1;
}
if (m_Bitmap.LoadBitmap(IDB_WEBBUTTON))
{
SendMessage(BM_SETIMAGE, IMAGE_BITMAP,
(LPARAM)m_Bitmap.GetSafeHandle());
}
else
{
TRACE("Unable to load bitmap for button.");
}
EnableToolTips(TRUE);
return 0;
}
void CWebButtonCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
RelayToolTipEvent(GetCurrentMessage());
COleControl::OnMouseMove(nFlags, point);
}
void CWebButtonCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
RelayToolTipEvent(GetCurrentMessage());
COleControl::OnLButtonDown(nFlags, point);
}
void CWebButtonCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
RelayToolTipEvent(GetCurrentMessage());
COleControl::OnLButtonUp(nFlags, point);
}
BOOL CWebButtonCtrl::OnToolNeedText(UINT id, NMHDR * pNMHDR, LRESULT * pResult)
{
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
::strcpy(pTTT->szText, m_strToolTipText);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// Property changed handlers
void CWebButtonCtrl::OnToolTipEnabledChanged()
{
SetModifiedFlag();
}
void CWebButtonCtrl::OnToolTipTextChanged()
{
SetModifiedFlag();
}
Figure 7 CCircle Hit-testing
/////////////////////////////////////////////////////////////////////////////
// CCircle hittesting
inline double Square(int n) { return (double(n) * double(n)); }
BOOL CCircle::HitTest(const CPoint& Point) const
{
CPoint Diff = m_CenterPoint - Point;
return ((Square(Diff.x) + Square(Diff.y)) <= Square(m_nRadius));
}
Figure 8 DTDemoView
/////////////////////////////////////////////////////////////////////////////
// DTDemoView.cpp : implementation of the CDTDemoView class
?
?
?
/////////////////////////////////////////////////////////////////////////////
// CDTDemoView HitTest
const CCircle* CDTDemoView::HitTest(const CPoint& Point)
{
CDTDemoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// Check in reverse order to deal with clipping.
const CCircle *pCircleHit = NULL;
for (int n = pDoc->GetCircleCount() - 1; n >= 0 && pCircleHit == NULL; n--)
{
if (pDoc->GetCircle(n).HitTest(Point))
{
pCircleHit = &(pDoc->GetCircle(n));
}
}
return pCircleHit;
}
/////////////////////////////////////////////////////////////////////////////
// CDTDemoView drawing
void CDTDemoView::OnDraw(CDC* pDC)
{
CDTDemoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
for (int n = 0; n < pDoc->GetCircleCount(); n++)
{
pDoc->GetCircle(n).Draw(pDC);
}
}
/////////////////////////////////////////////////////////////////////////////
// CDTDemoView diagnostics
#ifdef _DEBUG
void CDTDemoView::AssertValid() const
{
CView::AssertValid();
}
void CDTDemoView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CDTDemoDoc* CDTDemoView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDTDemoDoc)));
return (CDTDemoDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CDTDemoView message handlers
void CDTDemoView::OnInitialUpdate()
{
CView::OnInitialUpdate();
CRect ClientRect(0, 0, 1000, 1000);
if (m_ToolTip.Create(this, TTS_ALWAYSTIP) && m_ToolTip.AddTool(this))
{
m_ToolTip.SendMessage(TTM_SETMAXTIPWIDTH, 0, SHRT_MAX);
m_ToolTip.SendMessage(TTM_SETDELAYTIME, TTDT_AUTOPOP, SHRT_MAX);
m_ToolTip.SendMessage(TTM_SETDELAYTIME, TTDT_INITIAL, 200);
m_ToolTip.SendMessage(TTM_SETDELAYTIME, TTDT_RESHOW, 200);
}
else
{
TRACE("Error in creating ToolTip");
}
}
BOOL CDTDemoView::OnToolTipNeedText(UINT id, NMHDR * pNMHDR, LRESULT * pResult)
{
BOOL bHandledNotify = FALSE;
CPoint CursorPos;
VERIFY(::GetCursorPos(&CursorPos));
ScreenToClient(&CursorPos);
CRect ClientRect;
GetClientRect(ClientRect);
// Make certain that the cursor is in the client rect, because the
// mainframe also wants these messages to provide tooltips for the
// toolbar.
if (ClientRect.PtInRect(CursorPos))
{
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
m_pCircleHit = HitTest(CursorPos);
if (m_pCircleHit)
{
// Adjust the text by filling in TOOLTIPTEXT
CString strTip;
const CPoint& Center = m_pCircleHit->GetCenter();
COLORREF Color = m_pCircleHit->GetColor();
strTip.Format("Center: (%d, %d)\nRadius: %d\nColor: (%d, %d, %d)",
Center.x, Center.y, m_pCircleHit->GetRadius(),
(int)GetRValue(Color), (int)GetGValue(Color),
(int)GetBValue(Color));
ASSERT(strTip.GetLength() < sizeof(pTTT->szText));
::strcpy(pTTT->szText, strTip);
// Set the text color to same color as circle
m_ToolTip.SendMessage(TTM_SETTIPTEXTCOLOR, Color, 0L);
}
else
{
pTTT->szText[0] = 0;
}
bHandledNotify = TRUE;
}
return bHandledNotify;
}
BOOL CDTDemoView::PreTranslateMessage(MSG* pMsg)
{
if (::IsWindow(m_ToolTip.m_hWnd) && pMsg->hwnd == m_hWnd)
{
switch(pMsg->message)
{
case WM_LBUTTONDOWN:
case WM_MOUSEMOVE:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
m_ToolTip.RelayEvent(pMsg);
break;
}
}
return CView::PreTranslateMessage(pMsg);
}
void CDTDemoView::OnMouseMove(UINT nFlags, CPoint point)
{
if (::IsWindow(m_ToolTip.m_hWnd))
{
const CCircle* pCircleHit = HitTest(point);
if (!pCircleHit || pCircleHit != m_pCircleHit)
{
// Use Activate() to hide the tooltip.
m_ToolTip.Activate(FALSE);
}
if (pCircleHit)
{
m_ToolTip.Activate(TRUE);
m_pCircleHit = pCircleHit;
}
}
CView::OnMouseMove(nFlags, point);
}
Figure 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; // Not a valid index
static LPCSTR m_pszWndClass; // Registered class name
int m_nItemIndex; // Index of currently displayed listbox item
CListBox* m_pListBox; // Parent listbox
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)
{
// Register the window class if it has not already been registered by
// previous instantiation of 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;
// Don't add border to regular (non owner-draw) listboxes because
// owner-draw item automatically adds border.
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());
// Invalidate if new item.
if (m_nItemIndex != nItemIndex)
{
m_nItemIndex = nItemIndex;
InvalidateRect(NULL);
}
// Adjust window position and visibility.
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())
{
// Let the listbox do the real drawing.
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
{
// Do all of the drawing ourselves
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);
}
// Draw background
DC.FillSolidRect(ClientRect, clrBackground);
// Draw text of item
CString strItem;
m_pListBox->GetText(m_nItemIndex, strItem);
ASSERT(!strItem.IsEmpty());
DC.SetBkMode(TRANSPARENT);
DC.TextOut(1, -1, strItem);
}
DC.RestoreDC(nSavedDC);
// Do not call CWnd::OnPaint() for painting messages
}
Figure 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; // Not a valid index
CPoint m_LastMouseMovePoint; // Last position of mouse cursor
BOOL m_bMouseCaptured; // Is mouse captured?
CTitleTip m_TitleTip; // TitleTip that gets displayed when necessary
// This method should be overridden by an owner-draw listbox.
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)
{
// Calculate the ideal rect for an item. The ideal rect is dependent
// on the length of the string. This only works for regular
// (non owner-draw)listboxes.
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())
{
// Calulate the ideal text length.
CClientDC DC(this);
CFont* pOldFont = DC.SelectObject(GetFont());
CSize ItemSize = DC.GetTextExtent(strItem);
DC.SelectObject(pOldFont);
// Take the maximum of regular width and ideal width.
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
{
// Adjust the rect for being near the edge of screen.
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())
{
// Make sure we capture mouse so we can detect when to turn off
// title tip.
if (!m_bMouseCaptured && GetCapture() != this)
{
CaptureMouse();
}
}
else
{
// The tip is invisible so release the mouse.
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)
{
// Temporarily disable mouse capturing because the base class may
// capture the mouse.
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:
// Make the active view because that is the default
// behaviour caused by WM_MOUSEACTIVATE when NO TitleTip
// is over this window.
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);
}
Figure 13 CODListBox
// ODListBox.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CODListBox window
#include "TitleTipListBox.h"
class CODListBox : public CTitleTipListBox
{
// Construction
public:
CODListBox();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CODListBox)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CODListBox();
protected:
const int m_nEdgeSpace; // Extra space surrounding text
const int m_nFontHeight; // Height of font
CFont m_Font; // Font used for displaying item
virtual int GetIdealItemRect(int nIndex, LPRECT lpRect);
// Generated message map functions
protected:
//{{AFX_MSG(CODListBox)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
// ODListBox.cpp : implementation file
//
#include "stdafx.h"
#include "TTDemo.h"
#include "ODListBox.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CODListBox
CODListBox::CODListBox()
: m_nEdgeSpace(4), m_nFontHeight(20)
{
VERIFY(m_Font.CreateFont(m_nFontHeight, 0, 0, 0, FW_BOLD, 0, 0, 0,
ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
"Arial"));
}
CODListBox::~CODListBox()
{
}
int CODListBox::GetIdealItemRect(int nIndex, LPRECT lpRect)
{
ASSERT(nIndex >= 0);
int nResult = GetItemRect(nIndex, lpRect);
if (nResult != LB_ERR)
{
CClientDC DC(this);
CFont* pOldFont = DC.SelectObject(&m_Font);
// Calculate the text length.
CString strItem;
GetText(nIndex, strItem);
CSize TextSize = DC.GetTextExtent(strItem);
// Take the maximum of the regular or ideal.
lpRect->right = max(lpRect->right,
lpRect->left + TextSize.cx + (m_nEdgeSpace * 2));
DC.SelectObject(pOldFont);
}
return nResult;
}
BEGIN_MESSAGE_MAP(CODListBox, CTitleTipListBox)
//{{AFX_MSG_MAP(CODListBox)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CODListBox message handlers
void CODListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
ASSERT_VALID(pDC);
int nSavedDC = pDC->SaveDC();
CString strItem;
if (lpDrawItemStruct->itemID != -1)
{
GetText(lpDrawItemStruct->itemID, strItem);
}
COLORREF TextColor;
COLORREF BackColor;
UINT nItemState = lpDrawItemStruct->itemState;
if (nItemState & ODS_SELECTED)
{
TextColor = RGB(255, 255, 255); // White
BackColor = RGB(255, 0, 0); // Red
}
else
{
TextColor = RGB(255, 0, 0); // Red
BackColor = RGB(255, 255, 255); // White
}
CRect ItemRect(lpDrawItemStruct->rcItem);
// Draw background
pDC->FillSolidRect(ItemRect, BackColor);
// Draw text
pDC->SetTextColor(TextColor);
pDC->SetBkMode(TRANSPARENT);
pDC->SelectObject(&m_Font);
ItemRect.left += m_nEdgeSpace;
pDC->DrawText(strItem, ItemRect,
DT_LEFT | DT_SINGLELINE | DT_VCENTER);
ItemRect.left -= m_nEdgeSpace;
// Draw focus rect if necessary
if (nItemState & ODS_FOCUS)
{
pDC->DrawFocusRect(ItemRect);
}
pDC->RestoreDC(nSavedDC);
}
void CODListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
lpMeasureItemStruct->itemHeight = m_nFontHeight + (m_nEdgeSpace * 2);
}
Figure 14 CTTDemoDlg
// TTDemoDlg.h : header file
/////////////////////////////////////////////////////////////////////////////
// CTTDemoDlg dialog
#include "TitleTipListBox.h"
#include "ODListBox.h"
class CTTDemoDlg : public CDialog
{
// Construction
public:
CTTDemoDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CTTDemoDlg)
enum { IDD = IDD_TTDEMO_DIALOG };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTTDemoDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
CTitleTipListBox m_RegListBox; // Regular listbox
CODListBox m_ODListBox; // Owner-draw listbox
// Generated message map functions
//{{AFX_MSG(CTTDemoDlg)
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
// TTDemoDlg.cpp : implementation file
#include "stdafx.h"
#include "TTDemo.h"
#include "TTDemoDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CTTDemoDlg dialog
CTTDemoDlg::CTTDemoDlg(CWnd* pParent /*=NULL*/)
: CDialog(CTTDemoDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CTTDemoDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CTTDemoDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTTDemoDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CTTDemoDlg, CDialog)
//{{AFX_MSG_MAP(CTTDemoDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTTDemoDlg message handlers
BOOL CTTDemoDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// Subclass regular listbox
HWND hwndRegListBox = ::GetDlgItem(GetSafeHwnd(), IDC_REGLISTBOX);
ASSERT(hwndRegListBox);
VERIFY(m_RegListBox.SubclassWindow(hwndRegListBox));
// Subclass owner-draw listbox
HWND hwndODListBox = ::GetDlgItem(GetSafeHwnd(), IDC_ODLISTBOX);
ASSERT(hwndODListBox);
VERIFY(m_ODListBox.SubclassWindow(hwndODListBox));
// Load both listboxes with items
static char* pszItemArray[] =
{
"The C++ Programming Language",
"C++ Primer",
"OLE Controls Inside Out",
"Inside OLE 2nd Edition",
"Inside ODBC",
"Code Complete",
"Rapid Software Development",
"The Design Of Everyday Things",
"Object-Oriented Analysis And Design",
"MFC Internals",
"Animation Techniques In Win32",
"Inside Visual C++",
"Writing Solid Code",
"Learn Java Now"
};
static int nItemArrayCount = sizeof(pszItemArray) / sizeof(pszItemArray[0]);
for (int n = 0; n < nItemArrayCount; n++)
{
VERIFY(m_RegListBox.AddString(pszItemArray[n]) != LB_ERR);
VERIFY(m_ODListBox.AddString(pszItemArray[n]) != LB_ERR);
}
return TRUE; // return TRUE unless you set the focus to a control
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CTTDemoDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CTTDemoDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
浙公网安备 33010602011771号