mfc listctrl控件,clistctrl控件
本文根据我在项目中的应用,谈谈CListCtrl的一些用法和技巧。读书的时候查了很多资料,零零碎碎做了一些记录。现在主要想做个总结,供以后参考。主要包括以下十三点:基本操作、获取选中行的行号、复选框操作、动态设置选中行的字体颜色、设置选中行的背景颜色、禁止拖动表头、首列居中、设置行高和字体、虚拟列表技术、点击表头时排序、上下移动、动态调整大小、避免闪烁。
分两篇文章来总结。本文重点总结:基本操作,获取选中行的行号,复选框操作,动态设置选中行的字体颜色,设置选中行的背景颜色。
1.基本操作
从以下四点介绍CListCtrl的基本操作:
设置列表视图的显示模式。
.CListCtrl有四种样式:LVS图标、LVS小图标、LVS列表和LSV报告,可以通过控件属性设置。本文中提到的所有属性都是LSV报告属性。
.扩展样式:
常用的扩展样式有三种:LVS_EX_FULLROWSELECT、LVS_EX_GRIDLINES、LVS_EX_CHECKBOXES,分别是选中一行时高亮显示主线、设置网格线、在项目前生成Ckeckbox控件。
使用SetExtendedStyle(style)函数设置扩展样式,使用GetExtendedStyle()函数获取样式,例如:
m_listInfo。SetExtendedStyle(LVS _ EX _全行选择 LVS _ EX _网格线);
.使用CListView时,需要在PreCreateWindow()函数中添加cs . style =LVS _ REPORT;
要将其设置为LVS _报表样式,否则插入无效。还有一种设置样式的方法,就是在OnInitialUpate()中获取CListCtrl的控制权,然后修改样式,如下图:
clist ctrl the ctrl=getlist ctrl();
theCtrl。ModifyStyle(0,LVS _报告);
插入操作
首先插入列:
int InsertColumn( int nCol,LPCTSTR lpszColumnHeading,int nFormat,int nWidth,int nSubItem)
插入列时,可以指明列号、列名、列名显示样式、列宽等信息。列号为0的列总是显示在左边,会有方法修改使其在剧中显示。通过设置nFormat属性,其他列可以显示在中间。
插入行:
int InsertItem( int nItem,LPCTSTRlpszItem)
直接插入一行,其中nItem表示行号,lpszItem表示该行第0列的信息。
设置:
BOOL SetItemText(int nItem,int nSubItem,LPCTSTR lpszText)
在nItem行中设置nSubItem列的信息(NITEM: 0,1,2,3.nSubItem:1,2,3……)
删除操作
有三种操作功能:
boodeleteallitems()-删除所有行
删除一行。
删除一列。
获取/设置属性函数
功能很多,就不一一介绍了。常用的有
GetitemCount()-获取插入信息的行数。
l设置项目状态(int link,uintstate,uintstatemask)-设置行状态,比如高亮显示。
等等
2.获取所选行的行号。
获取选中行的行号,然后进行处理,编程中经常用到。
当鼠标点击该项时,控件向父窗口发送NM_CLICK消息,其响应函数为onnmclickxxx (nmhdr * pnmhdr,lresult * preset),在其下编写代码获取鼠标点击的行号。
获取行号的方法有两种:第一种方法是使用GetFirstSelectedItemPosition和GetNextSelectedItem获取;第二种是先获取鼠标位置信息,然后调用HitTest函数找出行号。例子如下:
第一种方法,这个例子取自MSDN,修改后可以使用。
【cpp】查看plaincopyprint?
position pos=pList-GetFirstSelectedItemPosition();if(pos==NULL)trace 0( Noitemswereselected!\ n’);else { while(pos){ intn item=pList-GetNextSelectedItem(pos);TRACE1(Item%dwasselected!\n ,nItem);//youcouldodouownprocessingonnithere } } POSITION pos=pList-getfirstelecteditemposition();
if (pos==NULL)
TRACE0(未选择任何项目!\ n’);
while(位置)
int nItem=pList-GetNextSelectedItem(pos);
TRACE1(选择了项目%d!\n ,nItem);
//您可以在项目上进行自己的处理
} 第二种方法,该示例来自我的项目,可作修改后使用。查看plaincopyprint?
//获取单击所在的行号//找出鼠标位置DWORDdwPos=GetMessagePos();c point point(low word(dwPos),hi word(dwPos));m_listCtrl .屏幕客户端(点);//定义结构体lvhittestinfovinfolvinfo . pt=point//获取行号信息intnItem=m_listCtrl .HitTest(lvinfo);如果(nItem!=-1)m _ items El=lvinfo。iitem//当前行号//获取单击所在的行号
//找出鼠标位置
DWORD dwPos=GetMessagePos();
c点(低位字(dwPos),高位字(dw pos));
m_listCtrl .屏幕客户端(点);
//定义结构体
LVHITTESTINFO lvinfo
lvinfo.pt=point
//获取行号信息
int nItem=m_listCtrl .HitTest(lvinfo);
如果(nItem!=-1)
m _ items El=lvinfo.iItem//当前行号对于LVHITTESTINFO结构体,其有四个成员,在上述点击测试调用中,其第一个成员作为输入,另外三个作为输出。具体变量含义可查看MSDN。
【cpp】查看plaincopyprint?
typedef struct _ LVHITTESTINFO { point pt;uintflagsintiitemitisubitem } LVHITTESTINFO,* LPLVHITTESTINFOtypedef struct _ LVHITTESTINFO {
点pt;
无符号整型标志;
项目间;
国际标准化组织
} LVHITTESTINFO,* LPLVHITTESTINFO
3、复选框操作
有时需要在项目前面添加一个复选框,供用户选择,然后对所有选中项进行处理。
这里涉及到两个问题:第一个,如何添加检验盒风格;第二个,如何判断某一行的检验盒状态是否发生改变。
对于第一个问题,在基本操作里已经有所阐述了,即通过SetExtendedStyle函数添加LVS _ EX _复选框扩展风格。
这里重点探讨第二个问题,首先,操作复选框状态的有两个函数:
BOOL GetCheck(int nItem)获取复选框状态
BOOL SetCheck( int nItem,BOOL fCheck=TRUE ) -设置复选框状态
其次,我们要搞清楚以下四点:
当列表的项项目改变时,控件会向父窗口发送LVN _项目已更改消息,因此可以在LVN _项目已更改消息的响应函数中对复选框的状态进行处理(查询或设置)。
鼠标点击检验盒时,消息的顺序是NM_CLICK — LVN_ITEMCHANGED,即检验盒的状态是在NM _点击消息函数结束后才会发生变化,在NM _点击中使用GetCheck无效。
鼠标点击项目(非检验盒区域)时,消息的顺序是LVN _项目变更— NM_CLICK。
调用插入项目函数时,也会产生LVN _项目已更改消息。鉴于此,通常会自定义一个布尔型变量m_bHit来判断是点击操作还是插入操作,该变量初始赋假的,当有鼠标点击项目时赋没错,检测完是否有检验盒被点击后重新复位为错误。
示例如下所示:
【cpp】查看plaincopyprint?
void cxxx:OnNMClickXXXX(NMHDR * pnm HDR,LRESULT*pResult){//获取单击所在的行号//找出鼠标位置DWORDdwPos=GetMessagePos();c point point(low word(dwPos),hi word(dwPos));m_listCtrl .屏幕客户端(点);//定义结构体lvhittestinfovinfolvinfo . pt=point//获取行号信息intnItem=m_listCtrl .HitTest(lvinfo);如果(nItem!=-1)m _ items El=lvinfo。iitem//当前行号//判断是否点击在检验盒上如果(lvinfo。flags==LVHT _ ONITEMSTATEICON)m _ bHit=TRUE;* pResult=0;} void cxxx:onlvnitechanged xxxx(nm HDR * pnm HDR,LRESULT * pResult){ LPNMLISTVIEWpNMLV=reinterpret _ cast LPNMLISTVIEW(pnm HDR);//判断m_bHit,即是否点击了复选框if(m _ bHit){ m _ bHit=FALSE;//复位if(m_listCtrl .get check(m _ items El)){//CheckBox被选中//doyourownprocessing } else {//CheckBox取消选择//doyourownprocessing } } * pResult=0;} void cxxxx:OnNMClickXXXX(NMHDR * pnm HDR,LRESULT *pResult)
//获取单击所在的行号
//找出鼠标位置
DWORD dwPos=GetMessagePos();
c点(低位字(dwPos),高位字(dw pos));
m_listCtrl .屏幕客户端(点);
//定义结构体
LVHITTESTINFO lvinfo
lvinfo.pt=point
//获取行号信息
int nItem=m_listCtrl .HitTest(lvinfo);
如果(nItem!=-1)
m _ items El=lvinfo.iItem//当前行号
//判断是否点击在检验盒上
如果(lvinfo。flags==LVHT _ ONITEMSTATEICON)
m _ bHit=TRUE
* pResult=0;
void cxxx:onlvnitechanged xxxx(nm HDR * pNMHDR,LRESULT *pResult)
LPNMLISTVIEW pnm LV=reinterpret _ cast LPNMLISTVIEW(pnm HDR);
//判断m_bHit,即是否点击了检验盒
if(m_bHit)
m _ bHit=FALSE//复位
if(m_listCtrl .GetCheck(m_itemSel))
{//复选框被选中
//自己做处理
其他
{//复选框取消选择
//自己做处理
* pResult=0;
}
4、动态设置选中行的字体颜色有时可能需要设置某行的文字为特殊颜色,以表示某种特殊含义,比如正在下载的信息用绿色,暂停下载的用灰色。
首先,给出一个快乐的小熊的链接,这篇文章讲的非常好,主要是利用定制抽奖. http://www。代码项目。net-Stuff-to-Do-in-List-Controls-Using-Custom-Dra
然后,来谈谈我的方法,这里主要谈对选中行的字体颜色进行动态修改,当然也是我通过上面文章和自己实践结合得出的。
我们需要搞清楚以下几点(可以结合下面修改某一行的字体颜色的方法来看):
当控件绘制时,会发送NM_CUSTOMDRAW消息,该消息的消息响应函数为
【cpp】查看plaincopyprint?
void cxxx:OnNMCustomdrawXXXX(NMHDR * pnm HDR,LRESULT * pResult){ LPNMLVCUSTOMDRAWpLVCD=reinterpret _ cast LPNMLVCUSTOMDRAW(pnm HDR);//TODO:addyourcontrolnotificationhandlercode here * pResult=CDRF _多多默认;//………………} void cxxx:OnNMCustomdrawXXXX(NMHDR * pnm HDR,LRESULT *pResult)
LPNMLVCUSTOMDRAW pLVCD=reinterpret _ cast LPNMLVCUSTOMDRAW(pnm HDR);
//TODO:在此添加控件通知处理程序代码
* pResult=CDRF _多德默认;
//………………
}
其中,pNMHDR为输入参数,其指向NMLVCUSTOMDRAW结构体,该结构包含了很多信息,包括字体颜色、背景等等,特别是第一个成员,为NMCUSTOMDRAW结构体变量,其包含了当前绘图阶段(不知道怎么编译比较好),其可能的值如下图(截自MSDN)所示
预设为输出参数,该参数决定了接下来向窗子发送什么消息(与绘制有关的),通过发送该消息我们可以进入下一步需要的处理阶段。具体输出哪个值取决于当前绘图阶段,其可能的值如下图(截自MSDN)所示
有一点必须注意(英文的,我觉得看起来比翻译过来更精确):
要记住的一点是,在做任何其他事情之前,您必须始终检查绘制阶段,因为您的处理程序会收到许多消息,而绘制阶段决定了您的代码采取什么操作。
下面我们来看看如何修改某一行的字体颜色:
首先,我们应该明白要修改字体颜色,应该在预涂漆阶段来完成
因此,在消息响应函数中,我们首先判断是否处于油漆前阶段(即pLVCD-nmcd。dwdrawstage==CDDS _ PREPAINT),然后通过修改输出值预设的值来通知窗子我们需要处理每个项目的消息(即设置*pResult=CDRF_NOTIFYITEMDRAW)。
再次进入消息响应函数时,我们判断是否处于项目的油漆前阶段(即pLVCD-nmcd。dwdrawstage==CDDS _项目准备点),如果是则进行相关处理,即修改字体颜色等等。
处理完了后重新设置* pResult=CDRF _多德默认,表示我们不再需要其他特殊的消息了,默认执行即可。
示例如下:
【cpp】查看plaincopyprint?
void cxxx:OnNMCustomdrawXXXX(NMHDR * pnm HDR,LRESULT * pResult){ LPNMLVCUSTOMDRAWpLVCD=reinterpret _ cast LPNMLVCUSTOMDRAW(pnm HDR);* pResult=CDRF _多德默认;//第一件事——checkthedrawtege .如果“感觉控制”是油漆前阶段,//则tellwindowswwantmessagesforeveryitem .if(CDDS _ PREPAINT==pLVCD-nmcd。dwdraw stage){ * pResult=CDRF _ NOTIFYITEMDRAW;} else if(CDDS _ item prepaint==pLVCD-nmcd。dwdrawstage){//thisithenotificationmessageforanitem .//处理,将项目改变背景颜色如果(/*符合条件*/)pLVCD- clrText=RGB(255,0,255);* pResult=CDRF _多德默认;} } void cxxxx:OnNMCustomdrawXXXX(NMHDR * pnm HDR,LRESULT *pResult)
LPNMLVCUSTOMDRAW pLVCD=reinterpret _ cast LPNMLVCUSTOMDRAW(pnm HDR);
* pResult=CDRF _多德默认;
//第一件事——检查抽签阶段。如果是控件的预绘制阶段,
//然后告诉Windows我们需要每个项目的消息。
if(CDDS _ PREPAINT==pLVCD-nmcd . dwdrawstage)
* pResult=CDRF _ NOTIFYITEMDRAW;
else if(CDDS _项目准备点==pLVCD-nmcd . dwdrawtege)
//这是项目的通知消息。
//处理,改变项目的背景颜色
If( /*限定*/)
pLVCD- clrText=RGB(255,0,255);
* pResult=CDRF _多德默认;
}
上述面试方法主要用于设置静态字体颜色。当然,如果你的列表的信息是不断变化的(也就是用SetItemText不断修改),那么就会实现动态变化。否则,您需要在适当的位置调用redraw函数:
BOOL RedrawItems( int nFirst,int nLast)
意味着nFirst和nLast之间的线需要重画。
5.设置所选线条的背景颜色。
设置选中行的背景色,选中行可以用特殊颜色显示,便于了解当前正在处理哪一行。虽然有高亮,但是高亮是建立在专注的基础上的。如果您选择了一行,然后焦点移动,则无法判断您选择了哪一行。
设置选中行背景色的方法和第四节提到的修改字体颜色的方法类似,都是使用自定义绘制。这涉及到设置当前选中行为的特殊颜色,同时要恢复之前选中行的颜色,否则会很乱。因此,有必要记录先前选择的行和当前选择的行的行号。通过前面的总结我相信这是不难做到的。然后在当前选定的行和先前选定的行之间重新绘制。
例子如下:
【cpp】查看plaincopyprint?
voi xxxx:onnmclickxxx(NMHDR * pnm HDR,LRESULT * PRESULT){/. intnLast=max(m _ items El,m _ itemForeSel);m_listCtrl。RedrawItems(nFirst,n last);//在以前选择的项目和当前选择的项目之间重画* preset=0;} void cxxx:OnNMCustomdrawXXXX(NMHDR * pnm HDR,LRESULT * pResult){ LPNMLVCUSTOMDRAWpLVCD=reinterpret _ cast LPNMLVCUSTOMDRAW(pnm HDR);* pResult=CDRF _多德默认;//first thing-checkthedrawtege。如果“sthecontrol”是prepaint //stage,则tellwindowswewontmessagesforeveryitem。if(CDDS _ PREPAINT==pLVCD-nmcd . dwdraw stage){ * pResult=CDRF _ NOTIFYITEMDRAW;} Else if(cdds _ itemPrepaint==plvcd-nmcd . dwdrawstage){//this notification message for a nitem。//处理,改变项的背景色if(m _ items El==plvcd-nmcd . dwitemspec){//当前选中的项plvcd-clrtextbk=RGB(22)else if(m _ itemforesel==plvcd-nmcd . dwitemspec){//之前选中的项恢复为白色plvcd-clrtextbk=RGB (255,255,255);} * pResult=CDRF _多德默认;}}
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。