VC 虚拟列表.doc_第1页
VC 虚拟列表.doc_第2页
VC 虚拟列表.doc_第3页
VC 虚拟列表.doc_第4页
VC 虚拟列表.doc_第5页
已阅读5页,还剩16页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

VC/MFC虚拟列表控件2008-10-07 19:12一、什么是虚拟列表控件虚拟列表控件是指带有LVS_OWNERDATA风格的列表控件。二、为什么使用虚拟列表控件我们知道,通常使用列表控件CListCtrl,需要调用InsertItem把要显示的数据插入列表中,之后我们就不必关心数据在哪里了,这是因为控件自己开辟了内存空间来保存这些数据。现在假设我们要显示一个数据库,里面的信息量很大,有几十万条记录。通常有两种方法解决这个问题:1是仅仅在ListCtrl中插入少量的数据,比如100个,然后通过上一页下一页两个按钮进行控制,某一时刻显示的只是从xxx到xxx+100之间的记录。2是把所有数据全部插入到ListCtrl中,然后让用户通过滚动来查看数据。无疑,很多用户喜欢采用第二种方式,特别是对于已经排序的数据,用户只需用键盘输入某行的开头字符,就可以快速定位到某一行。但是,如果这样做,InsertItem插入数据的过程将是很漫长的,而且用户会看到ListCtrl刷新速度也很慢,而且所有数据都位于内存中消耗了大量的内存,当数据多达上万以后几乎是不能忍受的。为此,mfc特别提供了虚拟列表的支持。一个虚拟列表看起来和普通的ListCtrl一样,但是不用通过InsertItem来插入数据,它仅仅知道自己应该显示多少数据。但是它如何知道要显示什么数据呢?秘密就在于当列表控件需要显示某个数据的时候,它向父窗口要。假设这个列表控件包含100个元素,第10到20个元素(行)是可见的。当列表控件重画的时候 ,它首先请求父窗口给它第10个元素的数据,父窗口收到请求以后,把数据信息填充到列表提供的一个结构中,列表就可以用来显示了,显示第10个数据后,列表会继续请求下一个数据。在虚拟的样式下,ListCtrl可以支持多达DWORD个数据项。(缺省的listctrl控件最多支持int个数据项)。但是,虚拟列表的最大优点不在于此,而是它仅仅需要在内存中保持极少量的数据,从而加快了显示的速度。所以,在使用列表控件显示一个很大的数据库的情况下,采用虚拟列表最好不过了。不仅CListCtrl提供虚拟列表的功能, MFC的CListView类也有同样的功能。三、虚拟列表控件的消息 虚拟列表总共发送三个消息给父窗口:当它需要数据的时候,它发送LVN_GETDISPINFO消息。这是最重要的消息。当用户试图查找某个元素的时候,它发送LVN_ODFINDITEM消息;还有一个消息是LVN_ODCACHEHINT,用来缓冲数据,基本上很少用到这个消息。虚拟列表控件使用起来非常简单。它总共只有三个相关的消息,如果你直接使用CListCtrl,应该在对话框中响应这三个消息。如果你使用CListCtrl派生类,可以在派生类中响应这三个消息的反射消息。这三个消息分别是:(1)LVN_GETDISPINFO 控件请求某个数据 (2)LVN_ODFINDITEM 查找某个数据 (3)LVN_ODCACHEHINT 缓冲某一部分数据我们必须响应的消息是(1),多数情况下要响应(2),极少数的情况下需要响应(3)四、如何使用虚拟列表控件1、首先要创建控件,创建一个虚拟列表和创建一个正常的 CListCtrl差不多。先在资源编辑器里面添加一个list control资源。然后选中Owner data属性,然后给它捆绑一个CListCtrl变量。添加列,添加imagelist等都和使用正常的listctrl一样。2、给虚拟列表添加元素。假设 m_list 是这个列表的控制变量。通常的情况下这样添加数据:m_list.InsertItem(0, _T(Hello world);但是对于虚拟列表,不能这么做。只需告诉列表有多少个数据:/总共显示100行 m_list.SetItemCount(100);3、处理它的通知消息。五、如何响应虚拟列表的消息1、处理 LVN_GETDISPINFO 通知消息当虚拟列表控件需要某个数据的时候,它给父窗口发送一个 LVN_GETDISPINFO通知消息,表示请求某个数据。因此列表的所有者窗口(或者它自己)必须处理这个消息。例如派生类的情况 (CMyListCtrl是一个虚拟列表类对象):/这里处理的是反射消息 BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl) /AFX_MSG_MAP(CMyListCtrl) ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetdispinfo) /AFX_MSG_MAP END_MESSAGE_MAP()在LVN_GETDISPINFO的处理函数中,必须首先检查列表请求的是什么数据,可能的值包括:(1)LVIF_TEXT 必须填充 pszText (2)LVIF_IMAGE 必须填充 iImage (3)LVIF_INDENT 必须填充 iIndent (4)LVIF_PARAM 必须填充 lParam (5)LVIF_STATE 必须填充 state根据它的请求,填充所需的数据即可。/= 例子代码=下面的给出一个例子,填充的是列表所需的某个数据项的文字以及图像信息:LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; LV_ITEM* pItem= &(pDispInfo)-item;int iItemIndx= pItem-iItem;if (pItem-mask & LVIF_TEXT) /字符串缓冲区有效 switch(pItem-iSubItem) case 0: /填充数据项的名字 lstrcpy(pItem-pszText,m_ItemsiItemIndx.m_strItemText); break; case 1: /填充子项1 lstrcpy(pItem-pszText,m_ItemsiItemIndx.m_strSubItem1Text); break; case 2: /填充子项2 lstrcpy(pItem-pszText,m_ItemsiItemIndx.m_strSubItem2Text); break; /*注意,多数情况下要使用lstrcpyn ,因为最多复制字符的个数由pItem-cchTextMax给出: lstrcpyn(pItem-pszText, text, pItem-cchTextMax); */if (pItem-mask & LVIF_IMAGE) /是否请求图像 pItem-iImage= m_ItemsiItemIndx.m_iImageIndex;甚至连某行数据是否选中(当有checkbox的情况下)的信息也需要由用户自己来维护,例如: /是否显示该行的选择信息? if(IsCheckBoxesVisible() /自定义函数 pItem-mask |= LVIF_STATE; pItem-stateMask = LVIS_STATEIMAGEMASK; if(m_databaseitemid.m_checked) pItem-state = INDEXTOSTATEIMAGEMASK(2); else pItem-state = INDEXTOSTATEIMAGEMASK(1); 2、处理 LVN_ODFINDITEM 消息在资源管理器里面,定位到某个文件夹,会显示很多文件,如果按下键盘的A,则资源管理器会自动找到名字以 A打头的文件夹或者文件, 并选择该文件。继续按 A,如果还有其它名字以A打头的文件,则下一个文件被选中。如果输入 AB,则 AB打头的文件被选中。这就是列表控件的自动查找功能。当虚拟列表收到一个LVM_FINDITEM消息,它也会发送这个消息通知父窗口查找目标元素。要搜索的信息通过 LVFINDINFO 结构给出。它是 NMLVFINDITEM 结构的一个成员。当找到要搜索的数据后,应该把该数据的索引(行号)返回,如果没有找到,则返回-1。以对话框为例,响应函数大致如下:/= 例子代码= void CVirtualListDlg:OnOdfinditemList(NMHDR* pNMHDR, LRESULT* pResult) / pNMHDR 里面是要查找的元素的信息 / 要选中的目标元素的行号最后要保存在 pResult 中, 这是关键! NMLVFINDITEM* pFindInfo = (NMLVFINDITEM*)pNMHDR; /* pFindInfo-iStart 是查找的起始位置,一直到最后,然后从头开始,如果没有找到合适的,最终停留在iStart*/ *pResult = -1; /是否按照文字查找? if( (pFindInfo-lvfi.flags & LVFI_STRING) = 0 ) return; /这是我们要找的字符串 CString searchstr = pFindInfo-lvfi.psz; int startPos = pFindInfo-iStart;/保存起始位置 /判断是否最后一行 if(startPos = m_list.GetItemCount() startPos = 0; int currentPos=startPos; /开始查找 do if( _tcsnicmp(m_databasecurrentPos.m_name, searchstr, searchstr.GetLength() = 0) /选中这个元素,停止查找 *pResult = currentPos; break; currentPos+; /从头开始 if(currentPos = m_list.GetItemCount() currentPos = 0; while(currentPos != startPos); 显然,如果数据很多,必须实现一个快速查找的方法。关于pFindInfo-lvfi里面的信息的详细说明可以参考 MSDN。3、处理 LVN_ODCACHEHINT 消息。假如我们从数据库或者其它地方读取数据的速度比较慢,则可以利用这个消息,批量读取一些数据,然后根据请求,逐个提供给虚拟列表。LVN_ODCACHEHINT消息的用途就是给程序一个缓冲数据的机会。以提高程序的性能。/= 例子代码= 使用 ClassWizard 重载 OnChildNotify 函数,检查是否 LVN_ODCACHEHINT 消息,然后准备缓冲数据:NMLVCACHEHINT* pcachehint=NULL;NMHDR* phdr = (NMHDR*)lParam;if(phdr-code = LVN_ODCACHEHINT) pcachehint= (NMLVCACHEHINT*) phdr; /自定义函数,准备指定范围的数据到缓冲区 PrepCache(pcachehint-iFrom, pcachehint-iTo); else .注意,如果消息不是 LVN_ODCACHEHINT,则要传递给基类进行处理。五、如何修改ListCtrl显示的数据。由于是程序自己维护数据,所以只需修改数据库中的数据,然后调用CListCtrl:RedrawItems函数进行重画即可。六、数据的选择状态和选择框CListCtrl可以显示checkbox选择框。有些情况下是很有用的。对于正常的listctrl,用户可以用鼠标来修改某个元素的选择状态,但是对于虚拟列表就不行了。必须自己处理一些消息,然后自己保存数据的选中状态:void CVirtualListDlg:ToggleCheckBox(int item) m_databaseitem.m_checked = !m_databaseitem.m_checked; m_list.RedrawItems(item, item); 处理 LVN_KEYDOWN消息,添加对空格键 的响应,用于切换选择状态:void CVirtualListDlg:OnKeydownList(NMHDR* pNMHDR, LRESULT* pResult) LV_KEYDOWN* pLVKeyDown = (LV_KEYDOWN*)pNMHDR; if( pLVKeyDown-wVKey = VK_SPACE ) int item = m_list.GetSelectionMark(); if(item != -1) ToggleCheckBox(item); *pResult = 0; 然后处理 NM_CLICK 消息:void CVirtualListDlg:OnClickList(NMHDR* pNMHDR, LRESULT* pResult) NMLISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; LVHITTESTINFO hitinfo; hitinfo.pt = pNMListView-ptAction; int item = m_list.HitTest(&hitinfo); if(item != -1) /看看鼠标是否单击在 check box上面了? if( (hitinfo.flags & LVHT_ONITEMSTATEICON) != 0) ToggleCheckBox(item); *pResult = 0; 七、备注: 1、虚拟列表无法进行排序。 2、虚表的一个优点是容易保持和数据库的同步。修改数据库中的数据,然后重画list十分容易而且高效。3、虚表的另一个优点是可以根据需要产生数据。比如在某一列加上行号。CListCtrl大数据显示 分类: MFC 2009-03-12 12:21 1004人阅读 评论(0) 收藏 举报 CListCtrl是个很方便的东西,但是当数据大到一个程度(比如说10万条数据),显示速度就会非常的慢。解决办法就是用虚拟列表。 CListCtrl显示数据的原理是将需显示的所有数据拷贝在它内部的一块空间里,然后显示出来。一但数据量过大,拷贝的时间就会延长,显示速度当然也就非常慢了。而虚拟列表则不需要将显示数据拷贝到内部空间,它的做法是当需要显示某个数据时,才将数据拷入内部空间。看上去好像和普通CListCtrl的做法相同,实则大不一样。因为列表一屏的数据,最多也就几百行。也就是说虚拟列表每次最多也就只需要拷贝几百行的数据,对现在计算机的速度而言,速度的延迟是完全可以忽略的。 好了,原理说到这里。接下来该说做怎么做了。cpp:showcolumns view plaincopy102030405060708090100110120130140150class CVirtaulListCtrl : public CListCtrl DECLARE_DYNAMIC(CVirtaulListCtrl) public: CVirtaulListCtrl(); virtual CVirtaulListCtrl(); public: /导入数据 void ImportData(CStringArray *pDataArray) m_pDataArray = pDataArray; SetItemCount(m_pDataArray-GetSize(); protected: CStringArray *m_pDataArray; protected: DECLARE_MESSAGE_MAP() public: afx_msg void OnLvnGetdispinfo(NMHDR *pNMHDR, LRESULT *pResult) LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; LV_ITEM* pItem= &(pDispInfo)-item; int iItemIndex= pItem-iItem; /行号 int col = pItem-iSubItem; /列号 if(pItem-mask & LVIF_TEXT) if(col = 0) /序号 char numberStr10; itoa(iItemIndex+1, numberStr, 10); lstrcpyn(pItem-pszText, numberStr, pItem-cchTextMax); else if(col = 1) lstrcpyn(pItem-pszText, m_pDataArray-GetAt(iItemIndex), pItem-cchTextMax); ; 上面一共只有两个函数。一个是ImportData,作用是导入需要显示的数据。里面只有两条语句,第一条为获取数据指针,第二条为设置列表长度(一共有多少条数据)。这个是自定义函数,可以自定义函数名和导入的数据结构。第二个函数是OnLvnGetdispinfo。这个函数是事件函数,当列表中的一个单元格需显示的时候调用。使用时,还需要将列表控件的“所有者数据”属性设为“true”。MFC总结之CListCtrl用法及技巧(一)本文根据本人在项目中的应用,来谈谈CListCtrl的部分用法及技巧。当初学习时,查了很多资料,零零碎碎的作了些记录,现在主要是来做个总结,方便以后查阅。主要包括以下十三点内容:基本操作、获取选中行的行号、复选框操作、动态设置选中行的字体颜色、设置选中行的背景颜色、禁止拖动表头、让第一列居中显示、设置行高与字体、虚拟列表技术、点击表头时进行归类、向上与向下移动、动态调整大小问题、避免闪烁问题。 分为两篇来进行总结。本篇重点总结:基本操作、获取选中行的行号、复选框操作、动态设置选中行的字体颜色、设置选中行的背景颜色 1、基本操作 分别从下面四点来介绍CListCtrl的基本操作: 设置列表视图显示方式 . CListCtrl有四种样式:LVS_ICON、LVS_SMALLICON、LVS_LIST、LSV_REPORT,可通过控件属性来设置。本文所述均为LSV_REPORT属性。 . 扩展样式: 常用的扩展样式有三种:LVS_EX_FULLROWSELECT、LVS_EX_GRIDLINES、LVS_EX_CHECKBOXES,分别对应作用 选中某行时使正行高亮、设置网格线、item前生成Ckeckbox控件。 使用SetExtendedStyle(style)函数设置扩展样式,使用GetExtendedStyle()函数获取样式,如: m_listInfo.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); . 使用CListView时,需要在PreCreateWindow()函数中添加 cs.style | = LVS_REPORT;来将其设置为LVS_REPORT风格,否则插入无效。还用另一种方法来设置风格,即在OnInitialUpate()中获取CListCtrl控制权,然后修改风格,如下所示: CListCtrl &theCtrl =GetListCtrl(); theCtrl.ModifyStyle(0, LVS_REPORT); 插入操作 先插入列: 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) 删除操作 有三个操作函数: BOOL DeleteAllItems() -删除所有的行 BOOL DeleteItem(nItem) -删除某一行 BOOL DeleteColumn(nCol) -删除某一列 获取/设置属性函数 有很多函数了,就不一一介绍了。常用的有 int GetItemCount() - 获取已插入信息的行数 BOOL SetItemState(int iLink, UINTstate, UINTstateMask ) -设置行状态,如高亮显示等等等 2、获取选中行的行号 获取选中行的行号,然后对该行进行相关处理,这点在编程中用的非常多。 当鼠标单击item时,控件向父窗口发送NM_CLICK消息,其响应函数为OnNMClickXXXX(NMHDR *pNMHDR, LRESULT *pResult),在该函数下来编写代码获取鼠标点击的行号。 有两种方法来获取行号:第一种是使用GetFirstSelectedItemPosition和GetNextSelectedItem配合来获取;第二种是先获取鼠标位置信息,然后调用HitTest函数来找出行号。示例分别如下: 第一种方法,该示例截自MSDN,可作修改后使用。cpp view plaincopyPOSITION pos = pList-GetFirstSelectedItemPosition(); if (pos = NULL) TRACE0(No items were selected!n); else while (pos) int nItem = pList-GetNextSelectedItem(pos); TRACE1(Item %d was selected!n, nItem); / you could do your own processing on nItem here 第二种方法,该示例来自我的项目,可作修改后使用。cpp view plaincopy/获取单击所在的行号 /找出鼠标位置 DWORD dwPos = GetMessagePos(); CPoint point( LOWORD(dwPos), HIWORD(dwPos) ); m_listCtrl.ScreenToClient(&point); /定义结构体 LVHITTESTINFO lvinfo; lvinfo.pt = point; /获取行号信息 int nItem = m_listCtrl.HitTest(&lvinfo); if(nItem != -1) m_itemSel = lvinfo.iItem; /当前行号 对于LVHITTESTINFO 结构体,其有四个成员,在上述HitTest调用中,其第一个成员作为输入,另外三个作为输出。具体变量含义可查看MSDN。cpp view plaincopytypedef struct _LVHITTESTINFO POINT pt; UINT flags; int iItem; int iSubItem; LVHITTESTINFO, *LPLVHITTESTINFO; 3、复选框操作 有时需要在item前面添加一个CheckBox,供用户选择,然后对所有选中项进行处理。 这里涉及到两个问题:第一个,如何添加CheckBox风格;第二个,如何判断某一行的CheckBox状态是否发生改变。 对于第一个问题,在基本操作里已经有所阐述了,即通过SetExtendedStyle函数添加LVS_EX_CHECKBOXES扩展风格。 这里重点探讨第二个问题,首先,操作复选框状态的有两个函数: BOOL GetCheck(int nItem)-获取复选框状态 BOOL SetCheck( int nItem, BOOL fCheck = TRUE )-设置复选框状态其次,我们要搞清楚以下四点: 当列表的项item改变时,控件会向父窗口发送LVN_ITEMCHANGED消息,因此可以在LVN_ITEMCHANGED消息的响应函数中对复选框的状态进行处理(查询或设置)。 鼠标点击CheckBox时,消息的顺序是 NM_CLICK LVN_ITEMCHANGED,即CheckBox的状态是在 NM_CLICK消息函数结束后才会发生变化,在NM_CLICK中使用GetCheck无效。 鼠标点击Item(非CheckBox区域)时,消息的顺序是 LVN_ITEMCHANGED NM_CLICK。 调用InsertItem 函数时,也会产生LVN_ITEMCHANGED消息。鉴于此,通常会自定义一个BOOL型变量m_bHit 来判断是点击操作还是插入操作,该变量初始赋FALSE,当有鼠标点击item时赋TRUE, 检测完是否有CheckBox被点击后重新复位为FALSE。 示例如下所示:cpp view plaincopyvoid CXXXX:OnNMClickXXXX(NMHDR *pNMHDR, LRESULT *pResult) /获取单击所在的行号 /找出鼠标位置 DWORD dwPos = GetMessagePos(); CPoint point( LOWORD(dwPos), HIWORD(dwPos) ); m_listCtrl.ScreenToClient(&point); /定义结构体 LVHITTESTINFO lvinfo; lvinfo.pt = point; /获取行号信息 int nItem = m_listCtrl.HitTest(&lvinfo); if(nItem != -1) m_itemSel = lvinfo.iItem; /当前行号 /判断是否点击在CheckBox上 if(lvinfo.flags = LVHT_ONITEMSTATEICON) m_bHit = TRUE; *pResult = 0; void CXXXX:OnLvnItemchangedXXXX(NMHDR *pNMHDR, LRESULT *pResult) LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR); /判断m_bHit,即是否点击了CheckBox if(m_bHit) m_bHit = FALSE; /复位 if(m_listCtrl.GetCheck(m_itemSel) /CheckBox被选中 /do your own processing else /CheckBox取消选择 /do your own processing *pResult = 0; 4、动态设置选中行的字体颜色 有时可能需要设置某行的文字为特殊颜色,以表示某种特殊含义,比如正在下载的信息用绿色,暂停下载的用灰色。 首先,给出一个CodeProject的链接,这篇文章讲的非常好,主要是利用Custom Draw。/Articles/79/Neat-Stuff-to-Do-in-List-Controls-Using-Custom-Dra 然后,来谈谈我的方法,这里主要谈对选中行的字体颜色进行动态修改,当然也是我通过上面文章和自己实践结合得出的。 我们需要搞清楚以下几点(可以结合下面修改某一行的字体颜色的方法来看): 当控件绘制时,会发送NM_CUSTOMDRAW 消息,该消息的消息响应函数为cpp view plaincopyvoid CXXXX:OnNMCustomdrawXXXX(NMHDR *pNMHDR, LRESULT *pResult) LPNMLVCUSTOMDRAW pLVCD = reinterpret_cast(pNMHDR); / TODO: Add your control notification handler code here *pResult = CDRF_DODEFAULT; / 其中,pNMHDR为输入参数,其指向NMLVCUSTOMDRAW结构体,该结构包含了很多信息,包括字体颜色、背景等等,特别是第一个成员,为NMCUSTOMDRAW结构体变量,其包含了Current drawing stage(不知道怎么编译比较好),其可能的值如下图(截自MSDN)所示 pResult为输出参数,该参数决定了接下来向windows发送什么消息(与绘制有关的),通过发送该消息我们可以进入下一步需要的处理阶段。具体输出哪个值取决于Current drawing stage,其可能的值如下图(截自MSDN)所示 有一点必须注意(英文的,我觉得看起来比翻译过来更精确): One thing to keep in mind is you must always check the draw stage before doing anything else, because your handler will receive many messages, and the draw stage determines what action your code takes. 下面我们来看看如何修改某一行的字体颜色: 首先,我们应该明白要修改字体颜色,应该在pre-paint 阶段来完成 因此,在消息响应函数中,我们首先判断是否处于pre-paint stage(即pLVCD-nmcd.dwDrawStage = CDDS_PREPAINT),然后通过修改输出值pResult 的值来通知windows我们需要处理每个item的消息(即设置 *pResult = CDRF_NOTIFYITEMDRAW)。 再次进入消息响应函数时,我们判断是否处于Item的pre-paint stage(即pLVCD-nmcd.dwDrawStage = CDDS_ITEMPREPAINT),如果是则进行相关处理,即修改字体颜色等等。 处理完了后重新设置 *pResult = CDRF_DODEFAULT,表示我们不再需要其他特殊的消息了,默认执行即可。 示例如下:cpp view plaincopyvoid CXXXX:OnNMCustomdrawXXXX(NMHDR *pNMHDR, LRESULT *pResult) LPNMLVCUSTOMDRAW pLVCD = reinterpret_cast(pNMHDR); *pResult = CDRF_DODEFAULT; / First thing - check the draw stage. If its the controls pre-paint stage, / then tell Windows we want messages for every item. if ( CDDS_PREPAINT = pLVCD-nmcd.dwDrawStage ) *pResult = CDRF_NOTIFYITEMDRAW; else if ( CDDS_ITEMPREPAINT = pLVCD-nmcd.dwDrawStage ) / This is the notification message for an item. /处理,将item改变背景颜色 if( /*符合条件*/ ) pLVCD-clrText = RGB(255,0,255); *pResult = CDRF_DODEFAULT; 上面谈的方法主要用于设置静态字体颜色,当然,如果你的列表的信息在不断变化(即用SetItemText不断修改),那么也就实现了动态改变了,否则需要在合适的地方调用重绘函数: BOOL RedrawItems( int nFirst, int nLast )表示在nFirst和nLast之间的行需要进行重绘。 5、设置选中行的背景颜色 设置选中行的背景颜色,可以将选中行以特殊颜色显示,容易明白当前处理的是哪一行。尽管有高亮,但是高亮是基于焦点的,如果你选中了某一行,然后焦点转移了,这是就无法判断你选的是哪一行了。 设置选中行的背景颜色的方法和第四节中讲的修改字体颜色的方法是相似的,都是利用Custom Draw。这里涉及到设置当前选中行为特殊颜色,同时要恢复前一次选中行的颜色,否则就乱了。因此需要记录前一次选中行、当前选中行的行号,相信通过前面的总结,这点并不难实现。然后在当前选中行和前一次选中行之间进行重绘即可。 示例如下:cpp view plaincopyvoid CXXXX:OnNMClickXXXX(NMHDR *pNMHDR, LRESULT *pResult) / /重绘item,更改背景颜色 int nFirst = min(m_itemSel,m_itemForeSel); int nLast = max(m_itemSel,m_itemForeSel); m_listCtrl.RedrawItems(nFirst, nLast); /在前一次选中的item和当前选中的Item之间进行重绘 *pResult = 0; void CXXXX:OnNMCustomdrawXXXX(NMHDR *pNMHDR, LRESULT *pResult) LPNMLVCUSTOMDRAW pLVCD = reinterpret_cast(pNMHDR)

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论