CListCtrl控件使用方法总结

CListCtrl是列表控件类,列表控件的每一行叫做一个item,每一列叫做一个subitem。每一行和每一列都有个ID号,可以确定唯一的单元格。

最近使用了这个控件,有心得总结如下:

(Dialog模式)

1. 创建列表控件.

定义一个成员变量:CListCtrl *m_pListCtrl;

在初始化对话框的时候创建列表,也就是在OnInitDialog()中创建(在哪里创建没有规定,只要符合对象和资源创建的规则即可。)

m_pListCtrl=new CListCtrl();

m_pListCtrl->Create();

m_pListCtrl->SetExtendedStyle();

Create函数有四个参数,DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID 。第一个参数可以是一些值的组合,用来定义列表的样式,这些值MSDN有详细说明,我只举一个简单的例子,更多的查看MSDN。例如第一个参数使用 LVS_REPORT,则表示列表有标题,或者说有列头,很多其他的样式必须是和这个样式搭配使用才有效。第二个参数是列表的坐标和大小,这个矩形框就表示列表的矩形框。第三个参数表示这个列表的父类,如果列表在对话框上或者是在试图上,这个参数可以是this。第四个参数是列表的资源号。

SetExtendedStyle函数只有一个参数,是一些值的组合,用来设置列表的扩展样式,这些值MSDN有详细的说明,我只介绍两个比较常用的。 LVS_EX_GRIDLINES :列表显示网格,只适用于LVS_REPORT 风格。LVS_EX_FULLROWSELECT:当一个item被选中时,它的所有subitems也处于被选中状态,点击任意一个subitem,则可同时选中整个行. 只适用于LVS_REPORT 风格。

2.构建列表

构建列表也就是两个操作,插入列和插入行,前面说过,一个列就是一个subitem,一行就是一个item。

m_pListCtrl->InsertColumn(0,"第一列");

列索引从0开始,InsertColumn函数将在列表中建立一个列,如果数据有三列,就调用三次此函数,索引分别是0,1,2。

m_pListCtrl->InsertItem(0,"第一行");

行索引也从0开始,InsertItem函数在列表中建立一行,且“第一行”的字样显示在的一列中,其他各列为空,如果要在除第一列以外的列中插入数据,调用SetItemText()函数,这个函数有三个参数,第一个参数表示要在第几行插入,第二个参数表示要在第几列插入,第三个参数表示要插入的内容。

可以设定列宽:

LVCOLUMN lvcolumn;
m_pListCtrl->GetColumn(0,&lvcolumn);
lvcolumn.mask=LVCF_WIDTH;
lvcolumn.cx=335;
m_pListCtrl->SetColumn(0,&lvcolumn);

表示将列宽设定为335像素。

3.操作列表

这里主要介绍一个比较有用的函数SubItemHitTest()

当鼠标停留在列表框上时,此函数会返回鼠标所在的行号,和鼠标所在的列号。

LVHITTESTINFO linfo;
DWORD dwPos = GetMessagePos();
CPoint point(LOWORD(dwPos),HIWORD(dwPos));
m_pListCtrl->ScreenToClient(&point);
linfo.pt=point;
linfo.flags=LVHT_ABOVE;
int iItem=m_pListCtrl->SubItemHitTest(&linfo);

行号保存在linfo.iItem中,列号保存在linfo.iSubItem中,此时可以调用GetItemText()函数获得这个单元格的内容了。

这个方法常用在列表的NM_CLICK和NM_DBLCLK事件中。

此类消息为:

ON_NOTIFY(NM_CLICK, IDC, OnFun)

函数原型:

void OnFun(NMHDR *pNMHDR, LRESULT *pResult)
{
*pResult = 0;
}

4.列表中的CheckBox

列表有多中风格,带CheckBox是其中常见的一种,设置这种风格的列表只需要在调用SetExtendedStyle函数的时候设置LVS_EX_CHECKBOXES。对CheckBox最常见的操作就是选中和取消,可能是我的知识贫乏,到目前,我还没有找到专门的消息处理这两个操作。要处理这样的操作,我使用下面的方法。

响应列表的NM_CLICK消息,在这个消息处理函数中,判断鼠标点击的位置是文本还是CheckBox,代码如下:

UINT nFlag;
DWORD dwPos = GetMessagePos();
CPoint point(LOWORD(dwPos),HIWORD(dwPos));
m_pList1->ScreenToClient(&point);
m_pList1->HitTest ( point , &nFlag ) ;

如果nFlag==LVHT_ONITEMSTATEICON ,说明鼠标点中了CheckBox。本可以调用GetCheck函数来获得CheckBox的状态,但是很可惜,CheckBox的状态似乎是在 NM_CLICK消息函数结束以后才会改变。所以,在NM_CLICK的消息处理函数中获得CheckBox的状态是没有改变之前的。

还有一点需要注意,假设现在目前CheckBox的状态是选中,那么,当你点击两下鼠标的时候,CheckBox还是选中状态,而且 NM_CLICK消息处理函数被执行了两次,所以,结果是正确的。但是当你点击两下鼠标时速度比较快,那么系统会把两次单击鼠标看作一次双击,这样,NM_CLICK的消息处理函数只会执行一次,但是,注意但是,CheckBox的状态却改变了两次。因此,这个时候你看到的CheckBox的状态和程序的结果就相反了。要解决这个问题,就需要在NM_DBLCLK的消息函数中做相应的工作。

以上若有不足之处,希望各位高手指正。

2009/04/01补充:

禁止列表头调整大小,需要派生一个CListCtrl类,重载一下函数为:

BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
HD_NOTIFY *pHDN = (HD_NOTIFY*)lParam;

switch (((NMHDR*)lParam)->code)
{
case HDN_BEGINTRACKW:
case HDN_BEGINTRACKA:
case HDN_DIVIDERDBLCLICKA:
case HDN_DIVIDERDBLCLICKW:
*pResult = TRUE; // disable tracking
return TRUE;
}

return CListCtrl::OnNotify(wParam, lParam, pResult);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CListCtrl 控件的表头默认只能显示一行,如果需要实现多行显示,可以通过继承 CHeaderCtrl 类并重写其 OnPaint 函数来实现。 具体实现步骤如下: 1. 定义一个新的类,继承自 CHeaderCtrl 类。 2. 在该类的头文件中添加一个变量,用于保存每个表头项的高度。 3. 在该类的构造函数中,设置表头的高度并获取每个表头项的高度。 4. 重写 OnPaint 函数,绘制多行表头。 下面是一个示例代码: ```cpp class CMultiLineHeaderCtrl : public CHeaderCtrl { public: CMultiLineHeaderCtrl(); virtual ~CMultiLineHeaderCtrl(); protected: int m_nHeaderHeight; // 表头高度 CArray<int, int> m_arrHeaderItemHeight; // 表头项高度 afx_msg void OnPaint(); DECLARE_MESSAGE_MAP() }; CMultiLineHeaderCtrl::CMultiLineHeaderCtrl() { m_nHeaderHeight = 50; // 设置表头高度 for (int i = 0; i < GetItemCount(); i++) { HDITEM hdi; hdi.mask = HDI_HEIGHT; GetItem(i, &hdi); m_arrHeaderItemHeight.Add(hdi.cy); // 获取每个表头项的高度 } } CMultiLineHeaderCtrl::~CMultiLineHeaderCtrl() { } BEGIN_MESSAGE_MAP(CMultiLineHeaderCtrl, CHeaderCtrl) ON_WM_PAINT() END_MESSAGE_MAP() void CMultiLineHeaderCtrl::OnPaint() { CPaintDC dc(this); CRect rc; GetClientRect(&rc); // 绘制表头背景 CBrush brush(GetSysColor(COLOR_3DFACE)); dc.FillRect(rc, &brush); // 绘制表头项 int nOffset = 0; for (int i = 0; i < GetItemCount(); i++) { HDITEM hdi; TCHAR szText[255]; hdi.mask = HDI_TEXT | HDI_FORMAT; hdi.pszText = szText; hdi.cchTextMax = sizeof(szText) / sizeof(TCHAR); GetItem(i, &hdi); // 计算表头项的矩形区域 CRect rcItem(nOffset, 0, nOffset + GetColumnWidth(i), m_arrHeaderItemHeight[i]); // 绘制表头项的背景 CBrush brushItem(GetSysColor(COLOR_BTNFACE)); dc.FillRect(rcItem, &brushItem); // 绘制表头项的文本 dc.SetBkMode(TRANSPARENT); dc.DrawText(szText, -1, rcItem, DT_CENTER | DT_SINGLELINE | DT_VCENTER); // 更新表头项的位置偏移量 nOffset += GetColumnWidth(i); } // 绘制表头分隔线 nOffset = 0; for (int i = 0; i < GetItemCount() - 1; i++) { CRect rcDivider(nOffset + GetColumnWidth(i) - 1, 0, nOffset + GetColumnWidth(i), m_nHeaderHeight); dc.FillRect(rcDivider, &brush); nOffset += GetColumnWidth(i); } } ``` 在使用该类的时候,只需要将 CListCtrl 控件的表头替换为 CMultiLineHeaderCtrl 控件即可实现多行表头的显示: ```cpp CMultiLineHeaderCtrl* pHeaderCtrl = new CMultiLineHeaderCtrl(); pHeaderCtrl->SubclassDlgItem(IDC_LIST_HEADER, this); ``` 其中,IDC_LIST_HEADER 是 CListCtrl 控件的表头控件的 ID。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值