新建一个对话框工程,并添加一个CListCtrl控件,并关联一个成员变量m_List。
ListView_SetExtendedListViewStyle(m_List.GetSafeHwnd(), m_List.GetExStyle() | LVS_EX_CHECKBOXES);
在OnInitDialog()中添加如下代码:
m_List.InsertColumn(0,"Name",LVCFMT_LEFT,150);
m_List.InsertColumn(1,"Sex",LVCFMT_LEFT,200);
m_List.InsertItem(0, "ZhangSan");
m_List.InsertItem(1, "LiSi");
为ListCtrl控件添加LVN_ITEMCHANGED消息。系统生成如下代码:
void CXXXDlg::OnLvnItemchangedList1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
}
void CXXXDlg::OnLvnItemchangedList1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
// TODO: Add your control notification handler code here
/*
typedef struct tagNMLISTVIEW
{
NMHDR hdr;
int iItem;
int iSubItem;
UINT uNewState;
UINT uOldState;
UINT uChanged;
POINT ptAction;
LPARAM lParam;
} NMLISTVIEW, *LPNMLISTVIEW;
*/
if((pNMLV->uOldState & INDEXTOSTATEIMAGEMASK(1)) /* old state : unchecked */
&& (pNMLV->uNewState & INDEXTOSTATEIMAGEMASK(2)) /* new state : checked */
)
{
TRACE("Item %d is checked\n", pNMLV->iItem);
}
else if((pNMLV->uOldState & INDEXTOSTATEIMAGEMASK(2)) /* old state : checked */
&& (pNMLV->uNewState & INDEXTOSTATEIMAGEMASK(1)) /* new state : unchecked */
)
{
TRACE("Item %d is unchecked\n", pNMLV->iItem);
}
else
{
TRACE("Item %d does't change the check-status\n", pNMLV->iItem);
}
*pResult = 0;
}
在debug环境下,改变checkbox的选中状态,查看输出信息。
OK.
http://hi.baidu.com/550189285/blog/item/e92e7e2901f4f8f499250a58.html
在默认的列表控件中包含的CheckBox是在项的开始,很多时候我们想把它显示在末尾,就只有对列表控件进行重绘操作了。
在对CListCtrl重绘时,我们不能够响应WM_DRAWITEM,这样会得到一个ASSERT(FALSE)的断言错误。解决的方法是对DRAWITEM虚函数进行重写。下面是我自己写的一个下例子,但是只要你选择的是复选框所在的列,不管是不是在复选框上,都会选中该复选框,这种方法感觉很不自然。提出来,希望大家给我指出要改进的地方,以及帮助那些想重绘CListCtrl的朋友理下思路,代码如下:
//.H
#if !defined(AFX_LISTCTRLCHECKBOX_H__3CA00E08_E3FC_4E62_B787_E3DCC31E0C5D__INCLUDED_)
#define AFX_LISTCTRLCHECKBOX_H__3CA00E08_E3FC_4E62_B787_E3DCC31E0C5D__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// ListCtrlCheckBox.h : header file
//
/
// ListCtrlCheckBox window
#define MAX_LISTITEM 1000
class ListCtrlCheckBox : public CListCtrl
{
// Construction
public:
ListCtrlCheckBox();
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(ListCtrlCheckBox)
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~ListCtrlCheckBox();
// Generated message map functions
protected:
//{{AFX_MSG(ListCtrlCheckBox)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
//Attribute
private:
BOOL m_bItemCheckState[MAX_LISTITEM];
//Operations
public:
//自绘列表控件
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
//取得被选中的第一项
int GetFirsetSelectedItem();
//返回下一个选中项
int GetNextSelectedItem(int nItem);
//判断某项的选择状态
BOOL GetCheckBoxItemState(int nItem);
//设置某项的选择状态
BOOL SetCheckBoxItemState(int nItem,BOOL bNewState);
};
/
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_LISTCTRLCHECKBOX_H__3CA00E08_E3FC_4E62_B787_E3DCC31E0C5D__INCLUDED_)
//.CPP
// ListCtrlCheckBox.cpp : implementation file
//
#include "stdafx.h"
#include "ListCtrlCheck.h"
#include "ListCtrlCheckBox.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// ListCtrlCheckBox
ListCtrlCheckBox::ListCtrlCheckBox()
{
//初始化m_bItemCheckState全为FALSE
memset(m_bItemCheckState,0,sizeof(m_bItemCheckState));
}
ListCtrlCheckBox::~ListCtrlCheckBox()
{
}
BEGIN_MESSAGE_MAP(ListCtrlCheckBox, CListCtrl)
//{{AFX_MSG_MAP(ListCtrlCheckBox)
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// ListCtrlCheckBox message handlers
void ListCtrlCheckBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
if (lpDrawItemStruct->CtlType != ODT_LISTVIEW)
return;
RECT rectiSubItem = {0};
RECT rectCheckBox = {0};
char szBuffer[50] = {0};
int nTotalColumn = 0;
CHeaderCtrl* pListHeader = NULL;
LV_ITEM lvi = {0};
pListHeader = (CHeaderCtrl*)GetDlgItem(0);
nTotalColumn = pListHeader->GetItemCount();
//最后一列是要显示复选框的一列
pListHeader->GetItemRect(nTotalColumn - 1,&rectCheckBox);
//循环地绘制列表控件各个子项
for (int iColumn = 0;iColumn < nTotalColumn;++iColumn)
{
lvi.mask = LVIF_TEXT | LVIF_PARAM;
lvi.iItem = lpDrawItemStruct->itemID ;
lvi.iSubItem = iColumn;
lvi.pszText = szBuffer ;
lvi.cchTextMax = sizeof(szBuffer);
VERIFY(GetItem(&lvi));
pListHeader->GetItemRect(iColumn,&rectiSubItem);
lpDrawItemStruct->rcItem.left = rectiSubItem.left;
lpDrawItemStruct->rcItem.right += rectiSubItem.right - rectiSubItem.left;
if (iColumn == nTotalColumn - 1)
{
rectCheckBox.top = lpDrawItemStruct->rcItem.top;
rectCheckBox.bottom = lpDrawItemStruct->rcItem.bottom;
//绘制复选框
if (m_bItemCheckState[lpDrawItemStruct->itemID])
{
DrawFrameControl(lpDrawItemStruct->hDC,&rectCheckBox,
DFC_BUTTON,DFCS_CHECKED);//已选中
}
else
{
DrawFrameControl(lpDrawItemStruct->hDC,&rectCheckBox,
DFC_BUTTON,DFCS_BUTTONCHECK);//未选中
}
}
else
{
DrawText(lpDrawItemStruct->hDC,szBuffer,strlen(szBuffer),
&lpDrawItemStruct->rcItem,DT_LEFT);
}
}
}
void ListCtrlCheckBox::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
RECT rectiSubItem = {0};
int nTotalColumn = 0;
int nItem = -1;
int nColumn = -1;
CHeaderCtrl* pListHeader = NULL;
pListHeader = (CHeaderCtrl*)GetDlgItem(0);
nTotalColumn = pListHeader->GetItemCount();
nItem = HitTest(point);//判断鼠标选择项
GetSubItemRect(nItem,nTotalColumn - 1,LVIR_BOUNDS,(CRect&)rectiSubItem);
if (PtInRect(&rectiSubItem,point))
{
m_bItemCheckState[nItem] = !m_bItemCheckState[nItem];
InvalidateRect(NULL,FALSE);
}
CListCtrl::OnLButtonDown(nFlags, point);
}
int ListCtrlCheckBox::GetFirsetSelectedItem()
{
int nItem = -1;
for (int iItem = 0;iItem < MAX_LISTITEM;++iItem)
{
if (m_bItemCheckState[iItem])
{
nItem = iItem;//返回第一个被选中项
break;
}
}
return nItem;
}
int ListCtrlCheckBox::GetNextSelectedItem(int nItem)
{
int nNextItem = -1;
for (int iItem = nItem + 1;iItem < MAX_LISTITEM;++iItem)
{
if (m_bItemCheckState[iItem])
{
nNextItem = iItem;
break;
}
}
return nNextItem;
}
BOOL ListCtrlCheckBox::GetCheckBoxItemState(int nItem)
{
return m_bItemCheckState[nItem];
}
BOOL ListCtrlCheckBox::SetCheckBoxItemState(int nItem,BOOL bNewState)
{
BOOL bOldState = FALSE;
bOldState = m_bItemCheckState[nItem];
m_bItemCheckState[nItem] = bNewState;
//刷新复选框状态
InvalidateRect(NULL,FALSE);
return bOldState;
}