最近在编程的时候,我老是碰到这种情况,在列表框中我想在字符串的前面加一个CHECK框,那样,我就可以选择我想要的字符串了。而且,有些时候还需要在一个字符串前面加更多的CHECK框,虽然这对很多人来说是不需要的。所以,我就写了这么一个类,类名是CMultiCheckListBox,这样的话,我上面的问题就会迎刃而解了。在这里面最重要的是一步是怎么在第一个CHECK框加了之后加第2个CHECK框。下面是实现这些的步骤:
* 添加成员变量,如下:
CMultiCheckListBox m_list;
* VC会创建下面的代码(如果没有的话,你就手工添加):
void ccharityreportdlg::dodataexchange(cdataexchange* pdx)
{
cdialog::dodataexchange(pdx);
//{{afx_data_map(ccharityreportdlg)
ddx_control(pdx, idc_list1, m_list);
//}}afx_data_map
}
* 这一步是添加地2个CHECK框,可以调用类中的setcheck(nindex, ncheck)函数,如下:
m_list.setcheck(nindex,1);
* 如果你需要的话,你就要设置地2个CHECK框了,可以调用类中的setmulticheck(nindex, ncheck) 函数,如下:
m_list.setmulticheck(nindex,1);
* 如果你想得到第1个CHECK框的状态的话,可以用getcheck(nindex)函数来完成,如下:
m_list.getcheck(nindex);
* 如果你想得到第2个CHECK框的状态的话,可以用getmulticheck(nindex)函数来完成,如下:
m_list.multigetcheck(nindex);
但是,这个类还是很简单的,它只能添加2个CHECK框,如果有读者有兴趣的话,完全可以把它给扩展了,形成更好的类,下面是类的所有代码,包括.H和.CPP文件:
//下面是H文件
#if !defined(AFX_MULTICHECKLISTBOX_H__D4D62F8F_E758_11D1_AE66_A0B807C10000__INCLUDED_)
#define AFX_MULTICHECKLISTBOX_H__D4D62F8F_E758_11D1_AE66_A0B807C10000__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// MultiCheckListBox.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CMultiCheckListBox window
class CMultiCheckListBox : public CCheckListBox
{
// Construction
public:
CMultiCheckListBox();
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMultiCheckListBox)
public:
virtual BOOL OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CMultiCheckListBox();
int CheckFromPoint(CPoint point, BOOL& bInCheck);
void InvalidateCheck(int nIndex);
void SetCheck(int nIndex, int nCheck);
int GetCheck(int nIndex);
int InMultiCheck(CPoint point, BOOL& bInMultiCheck);
void InvalidateMultiCheck(int nIndex);
int GetMultiCheck(int nIndex);
void SetMultiCheck(int nIndex, int nCheck);
// Generated message map functions
protected:
void PreDrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
//{{AFX_MSG(CMultiCheckListBox)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MULTICHECKLISTBOX_H__D4D62F8F_E758_11D1_AE66_A0B807C10000__INCLUDED_)
//下面是CPP文件
// MultiCheckListBox.cpp : implementation file
//
#include "stdafx.h"
#include "CheckBoxTest.h"
#include "MultiCheckListBox.h"
#include
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
class _AFX_CHECKLIST_STATE : public CNoTrackObject
{
public:
_AFX_CHECKLIST_STATE();
virtual ~_AFX_CHECKLIST_STATE();
HBITMAP m_hbitmapCheck;
CSize m_sizeCheck;
};
_AFX_CHECKLIST_STATE::_AFX_CHECKLIST_STATE()
{
CBitmap bitmap;
if (afxData.bWin4 || AfxGetCtl3dState()->m_pfnSubclassDlgEx != NULL)
VERIFY(bitmap.LoadBitmap(AFX_IDB_CHECKLISTBOX_95));
else
VERIFY(bitmap.LoadBitmap(AFX_IDB_CHECKLISTBOX_NT));
BITMAP bm;
bitmap.GetObject(sizeof (BITMAP), &bm);
m_sizeCheck.cx = bm.bmWidth / 3;
m_sizeCheck.cy = bm.bmHeight;
m_hbitmapCheck = (HBITMAP)bitmap.Detach();
}
_AFX_CHECKLIST_STATE::~_AFX_CHECKLIST_STATE()
{
if (m_hbitmapCheck != NULL)
::DeleteObject(m_hbitmapCheck);
}
EXTERN_PROCESS_LOCAL(_AFX_CHECKLIST_STATE, _afxChecklistState)
/////////////////////////////////////////////////////////////////////////////
// AFX_CHECK_DATA
struct AFX_CHECK_DATA
{
public:
int m_nCheck;
BOOL m_bEnabled;
DWORD m_dwUserData;
int m_nCheck2;
AFX_CHECK_DATA()
{
m_nCheck = 0;
m_bEnabled = TRUE;
m_dwUserData = 0;
m_nCheck2 = 0;
};
};
/////////////////////////////////////////////////////////////////////////////
// CMultiCheckListBox
CMultiCheckListBox::CMultiCheckListBox()
{
}
CMultiCheckListBox::~CMultiCheckListBox()
{
}
BEGIN_MESSAGE_MAP(CMultiCheckListBox, CCheckListBox)
//{{AFX_MSG_MAP(CMultiCheckListBox)
ON_WM_MEASUREITEM()
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMultiCheckListBox message handlers
void CMultiCheckListBox::PreDrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
_AFX_CHECKLIST_STATE* pChecklistState = _afxChecklistState;
if ((((LONG)lpDrawItemStruct->itemID) >= 0) &&
((lpDrawItemStruct->itemAction & (ODA_DRAWENTIRE | ODA_SELECT)) != 0))
{
int cyItem = GetItemHeight(lpDrawItemStruct->itemID);
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
COLORREF newBkColor = GetSysColor(COLOR_WINDOW);
BOOL fDisabled = !IsWindowEnabled() || !IsEnabled(lpDrawItemStruct->itemID);
if ((lpDrawItemStruct->itemState & ODS_SELECTED) && !fDisabled)
newBkColor = GetSysColor(COLOR_HIGHLIGHT);
COLORREF oldBkColor = pDC->SetBkColor(newBkColor);
int nCheck;
CDC bitmapDC;
HBITMAP hOldBitmap;
CRect rectCheck;
CRect rectItem;
CRect rectCheckBox;
if (bitmapDC.CreateCompatibleDC(pDC))
{
nCheck = GetCheck(lpDrawItemStruct->itemID);
hOldBitmap = (HBITMAP)::SelectObject(bitmapDC.m_hDC, pChecklistState->m_hbitmapCheck);
rectCheck = lpDrawItemStruct->rcItem;
rectCheck.left += 1;
rectCheck.top += 1 + max(0, (cyItem - pChecklistState->m_sizeCheck.cy) / 2);
rectCheck.right = rectCheck.left + pChecklistState->m_sizeCheck.cx;
rectCheck.bottom = rectCheck.top + pChecklistState->m_sizeCheck.cy;
rectItem = lpDrawItemStruct->rcItem;
rectItem.right = rectItem.left + pChecklistState->m_sizeCheck.cx + 2;
rectItem.right += pChecklistState->m_sizeCheck.cx + 2;
rectCheckBox = OnGetCheckPosition(rectItem, rectCheck);
ASSERT(rectCheck.IntersectRect(rectItem, rectCheckBox));
ASSERT((rectCheck == rectCheckBox) && (rectCheckBox.Size() == pChecklistState->m_sizeCheck));
CBrush first_brush(newBkColor);
pDC->FillRect(rectItem, &first_brush);
pDC->BitBlt(rectCheckBox.left, rectCheckBox.top,
pChecklistState->m_sizeCheck.cx, pChecklistState->m_sizeCheck.cy, &bitmapDC,
pChecklistState->m_sizeCheck.cx * nCheck, 0, SRCCOPY);
::SelectObject(bitmapDC.m_hDC, hOldBitmap);
}
pDC->SetBkColor(oldBkColor);
}
if (lpDrawItemStruct->itemData != 0)
{
AFX_CHECK_DATA* pState = (AFX_CHECK_DATA*)lpDrawItemStruct->itemData;
lpDrawItemStruct->itemData = pState->m_dwUserData;
}
lpDrawItemStruct->rcItem.left = lpDrawItemStruct->rcItem.left + pChecklistState->m_sizeCheck.cx + 2;
CCheckListBox::PreDrawItem(lpDrawItemStruct);
}
BOOL CMultiCheckListBox::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult)
{
switch (message)
{
case WM_DRAWITEM:
ASSERT(pLResult == NULL); // no return value expected
PreDrawItem((LPDRAWITEMSTRUCT)lParam);
break;
default:
return CCheckListBox::OnChildNotify(message, wParam, lParam, pLResult);
}
return TRUE;
}
PROCESS_LOCAL(_AFX_CHECKLIST_STATE, _afxChecklistState)
void CMultiCheckListBox::SetCheck(int nIndex, int nCheck)
{
ASSERT(::IsWindow(m_hWnd));
if (nCheck == 2)
{
if (m_nStyle == BS_CHECKBOX || m_nStyle == BS_AUTOCHECKBOX)
return;
}
LRESULT lResult = DefWindowProc(LB_GETITEMDATA, nIndex, 0);
if (lResult != LB_ERR)
{
AFX_CHECK_DATA* pState = (AFX_CHECK_DATA*)lResult;
if (pState == NULL)
pState = new AFX_CHECK_DATA;
pState->m_nCheck2 = nCheck;
VERIFY(DefWindowProc(LB_SETITEMDATA, nIndex, (LPARAM)pState) != LB_ERR);
InvalidateCheck(nIndex);
}
}
int CMultiCheckListBox::GetCheck(int nIndex)
{
ASSERT(::IsWindow(m_hWnd));
LRESULT lResult = DefWindowProc(LB_GETITEMDATA, nIndex, 0);
if (lResult != LB_ERR)
{
AFX_CHECK_DATA* pState = (AFX_CHECK_DATA*)lResult;
if (pState != NULL)
return pState->m_nCheck2; // check in first checkbox
}
return 0; // The default
}
void CMultiCheckListBox::InvalidateCheck(int nIndex)
{
CRect rect;
_AFX_CHECKLIST_STATE* pChecklistState = _afxChecklistState;
GetItemRect(nIndex, rect);
rect.right = rect.left + pChecklistState->m_sizeCheck.cx + 2;
rect.right = rect.left + pChecklistState->m_sizeCheck.cx + 2;
InvalidateRect(rect, FALSE);
}
void CMultiCheckListBox::SetMultiCheck(int nIndex, int nCheck)
{
ASSERT(::IsWindow(m_hWnd));
if (nCheck == 2)
{
if (m_nStyle == BS_CHECKBOX || m_nStyle == BS_AUTOCHECKBOX)
return;
}
LRESULT lResult = DefWindowProc(LB_GETITEMDATA, nIndex, 0);
if (lResult != LB_ERR)
{
AFX_CHECK_DATA* pState = (AFX_CHECK_DATA*)lResult;
if (pState == NULL)
pState = new AFX_CHECK_DATA;
pState->m_nCheck = nCheck;
VERIFY(DefWindowProc(LB_SETITEMDATA, nIndex, (LPARAM)pState) != LB_ERR);
InvalidateMultiCheck(nIndex);
}
}
int CMultiCheckListBox::GetMultiCheck(int nIndex)
{
ASSERT(::IsWindow(m_hWnd));
LRESULT lResult = DefWindowProc(LB_GETITEMDATA, nIndex, 0);
if (lResult != LB_ERR)
{
AFX_CHECK_DATA* pState = (AFX_CHECK_DATA*)lResult;
if (pState != NULL)
return pState->m_nCheck;
}
return 0; // The default
}
void CMultiCheckListBox::InvalidateMultiCheck(int nIndex)
{
CRect rect;
_AFX_CHECKLIST_STATE* pChecklistState = _afxChecklistState;
GetItemRect(nIndex, rect);
rect.left += pChecklistState->m_sizeCheck.cx + 2;
InvalidateRect(rect, FALSE);
}
int CMultiCheckListBox::CheckFromPoint(CPoint point, BOOL& bInCheck)
{
// assume did not hit anything
bInCheck = FALSE;
int nIndex = -1;
_AFX_CHECKLIST_STATE* pChecklistState = _afxChecklistState;
if ((GetStyle() & (LBS_OWNERDRAWFIXED|LBS_MULTICOLUMN)) == LBS_OWNERDRAWFIXED)
{
// optimized case for ownerdraw fixed, single column
int cyItem = GetItemHeight(0);
if (point.y < cyItem * GetCount())
{
nIndex = GetTopIndex() + point.y / cyItem;
if (point.x < pChecklistState->m_sizeCheck.cx + 2)
++bInCheck;
}
}
else
{
// general case for ownerdraw variable or multiple column
for (int i = GetTopIndex(); i < GetCount(); i++)
{
CRect itemRect;
GetItemRect(i, &itemRect);
if (itemRect.PtInRect(point))
{
nIndex = i;
if (point.x < itemRect.left + pChecklistState->m_sizeCheck.cx + 2)
++bInCheck;
break;
}
}
}
return nIndex;
}
int CMultiCheckListBox::InMultiCheck(CPoint point, BOOL& bInMultiCheck)
{
// assume did not hit anything
bInMultiCheck = FALSE;
int nIndex = -1;
_AFX_CHECKLIST_STATE* pChecklistState = _afxChecklistState;
if ((GetStyle() & (LBS_OWNERDRAWFIXED|LBS_MULTICOLUMN)) == LBS_OWNERDRAWFIXED)
{
// optimized case for ownerdraw fixed, single column
int cyItem = GetItemHeight(0);
if (point.y < cyItem * GetCount())
{
nIndex = GetTopIndex() + point.y / cyItem;
if (point.x < pChecklistState->m_sizeCheck.cx + 2 + (pChecklistState->m_sizeCheck.cx + 2))
++bInMultiCheck;
}
}
else
{
// general case for ownerdraw variable or multiple column
for (int i = GetTopIndex(); i < GetCount(); i++)
{
CRect itemRect;
GetItemRect(i, &itemRect);
if (itemRect.PtInRect(point))
{
nIndex = i;
if (point.x < itemRect.left + pChecklistState->m_sizeCheck.cx + 2)
++bInMultiCheck;
break;
}
}
}
return nIndex;
}
void CMultiCheckListBox::OnLButtonDown(UINT nFlags, CPoint point)
{
SetFocus();
// determine where the click is
BOOL bInCheck;
BOOL bInMultiCheck;
int nIndex = CheckFromPoint(point, bInCheck);
int n2Index = InMultiCheck(point, bInMultiCheck);
// if the item is disabled, then eat the click
if (!IsEnabled(nIndex))
return;
if (m_nStyle != BS_CHECKBOX && m_nStyle != BS_3STATE)
{
// toggle check mark automatically if check mark was hit
if (bInCheck)
{
CWnd* pParent = GetParent();
ASSERT_VALID(pParent);
int nModulo = (m_nStyle == BS_AUTO3STATE) ? 3 : 2;
int nCheck = GetCheck(nIndex);
nCheck = (nCheck == nModulo) ? nCheck - 1 : nCheck;
SetCheck(nIndex, (nCheck + 1) % nModulo);
InvalidateCheck(nIndex);
CListBox::OnLButtonDown(nFlags, point);
// Inform of check
pParent->SendMessage(WM_COMMAND,
MAKEWPARAM(GetDlgCtrlID(), CLBN_CHKCHANGE),
(LPARAM)m_hWnd);
return;
}
if (bInMultiCheck)
{
CWnd* pParent = GetParent();
ASSERT_VALID(pParent);
int nModulo = (m_nStyle == BS_AUTO3STATE) ? 3 : 2;
int nCheck = GetMultiCheck(nIndex);
nCheck = (nCheck == nModulo) ? nCheck - 1 : nCheck;
SetMultiCheck(nIndex, (nCheck + 1) % nModulo);
CListBox::OnLButtonDown(nFlags, point);
// Inform of check
pParent->SendMessage(WM_COMMAND,
MAKEWPARAM(GetDlgCtrlID(), CLBN_CHKCHANGE),
(LPARAM)m_hWnd);
return;
}
}
// do default listbox selection logic
CListBox::OnLButtonDown(nFlags, point);
}
译于2001年9月12号。我没有看完全部的代码,我希望读者能把它给看完,那样会对你更有好处。