MFC总结之CListCtrl用法及技巧

27 篇文章 0 订阅

下文是zwgdft 的总结文章,尽管有少量错误,但总结比较到位,收藏学习.

本文根据本人在项目中的应用,来谈谈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),在该函数下来编写代码获取鼠标点击的行号。

       有两种方法来获取行号:第一种是使用GetFirstSelectedItemPositionGetNextSelectedItem配合来获取;第二种是先获取鼠标位置信息,然后调用HitTest函数来找出行号。示例分别如下:

        第一种方法,该示例截自MSDN,可作修改后使用。

[cpp]  view plain copy
  1. POSITION pos = pList->GetFirstSelectedItemPosition();  
  2. if (pos == NULL)  
  3.    TRACE0("No items were selected!\n");  
  4. else  
  5. {  
  6.    while (pos)  
  7.    {  
  8.       int nItem = pList->GetNextSelectedItem(pos);  
  9.       TRACE1("Item %d was selected!\n", nItem);  
  10.       // you could do your own processing on nItem here  
  11.    }  
  12. }  
        第二种方法,该示例来自我的项目,可作修改后使用。
[cpp]  view plain copy
  1. //获取单击所在的行号  
  2. //找出鼠标位置  
  3. DWORD dwPos = GetMessagePos();  
  4. CPoint point( LOWORD(dwPos), HIWORD(dwPos) );  
  5. m_listCtrl.ScreenToClient(&point);  
  6.   
  7.  //定义结构体  
  8. LVHITTESTINFO lvinfo;  
  9. lvinfo.pt = point;  
  10.   
  11.  //获取行号信息  
  12. int nItem = m_listCtrl.HitTest(&lvinfo);  
  13. if(nItem != -1)  
  14.     m_itemSel = lvinfo.iItem;   //当前行号  
      对于LVHITTESTINFO 结构体,其有四个成员,在上述HitTest调用中,其第一个成员作为输入,另外三个作为输出。具体变量含义可查看MSDN。
[cpp]  view plain copy
  1. typedef struct _LVHITTESTINFO {  
  2.     POINT pt;  
  3.     UINT flags;  
  4.     int iItem;  
  5.     int iSubItem;  
  6. } 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 plain copy
  1. void CXXXX::OnNMClickXXXX(NMHDR *pNMHDR, LRESULT *pResult)  
  2. {  
  3.     //获取单击所在的行号  
  4.     //找出鼠标位置  
  5.     DWORD dwPos = GetMessagePos();  
  6.     CPoint point( LOWORD(dwPos), HIWORD(dwPos) );  
  7.     m_listCtrl.ScreenToClient(&point);  
  8.     //定义结构体  
  9.     LVHITTESTINFO lvinfo;  
  10.     lvinfo.pt = point;  
  11.     //获取行号信息  
  12.     int nItem = m_listCtrl.HitTest(&lvinfo);  
  13.     if(nItem != -1)  
  14.     m_itemSel = lvinfo.iItem;   //当前行号  
  15.   
  16.      //判断是否点击在CheckBox上  
  17.      if(lvinfo.flags == LVHT_ONITEMSTATEICON)  
  18.           m_bHit = TRUE;  
  19.   
  20.      *pResult = 0;  
  21. }  
  22.   
  23. void CXXXX::OnLvnItemchangedXXXX(NMHDR *pNMHDR, LRESULT *pResult)  
  24. {  
  25.     LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);  
  26.     //判断m_bHit,即是否点击了CheckBox  
  27.     if(m_bHit)  
  28.     {  
  29.             m_bHit = FALSE;     //复位  
  30.   
  31.         if(m_listCtrl.GetCheck(m_itemSel))  
  32.         {       //CheckBox被选中  
  33.             //do your own processing   
  34.         }  
  35.         else  
  36.         {      //CheckBox取消选择  
  37.             //do your own processing   
  38.         }  
  39.     }  
  40.   
  41.     *pResult = 0;  
  42. }  


  4、动态设置选中行的字体颜色

         有时可能需要设置某行的文字为特殊颜色,以表示某种特殊含义,比如正在下载的信息用绿色,暂停下载的用灰色。

         首先,给出一个CodeProject的链接,这篇文章讲的非常好,主要是利用Custom Draw。http://www.codeproject.com/Articles/79/Neat-Stuff-to-Do-in-List-Controls-Using-Custom-Dra    

         然后,来谈谈我的方法,这里主要谈对选中行的字体颜色进行动态修改,当然也是我通过上面文章和自己实践结合得出的。

        我们需要搞清楚以下几点(可以结合下面修改某一行的字体颜色的方法来看):

① 当控件绘制时,会发送NM_CUSTOMDRAW 消息,该消息的消息响应函数为

[cpp]  view plain copy
  1. void CXXXX::OnNMCustomdrawXXXX(NMHDR *pNMHDR, LRESULT *pResult)  
  2. {  
  3.     LPNMLVCUSTOMDRAW pLVCD = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR);  
  4.     // TODO: Add your control notification handler code here  
  5.     *pResult = CDRF_DODEFAULT;  
  6.        //………………  
  7.  }  

②其中,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 plain copy
  1. void CXXXX::OnNMCustomdrawXXXX(NMHDR *pNMHDR, LRESULT *pResult)  
  2. {  
  3.     LPNMLVCUSTOMDRAW pLVCD = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR);  
  4.     *pResult = CDRF_DODEFAULT;  
  5.   
  6.     // First thing - check the draw stage. If it's the control's pre-paint stage,   
  7.     // then tell Windows we want messages for every item.  
  8.     if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )  
  9.     {  
  10.         *pResult = CDRF_NOTIFYITEMDRAW;  
  11.     }  
  12.     else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )  
  13.     {  
  14.         // This is the notification message for an item.   
  15.     //处理,将item改变背景颜色  
  16.         if/*符合条件*/ )  
  17.         pLVCD->clrText = RGB(255,0,255);  
  18.           
  19.            *pResult = CDRF_DODEFAULT;  
  20.     }  
  21. }  

        上面谈的方法主要用于设置静态字体颜色,当然,如果你的列表的信息在不断变化(即用SetItemText不断修改),那么也就实现了动态改变了,否则需要在合适的地方调用重绘函数:

                         BOOL RedrawItems( int nFirst, int nLast )

表示在nFirst和nLast之间的行需要进行重绘。


  5、设置选中行的背景颜色


         设置选中行的背景颜色,可以将选中行以特殊颜色显示,容易明白当前处理的是哪一行。尽管有高亮,但是高亮是基于焦点的,如果你选中了某一行,然后焦点转移了,这是就无法判断你选的是哪一行了。

        设置选中行的背景颜色的方法和第四节中讲的修改字体颜色的方法是相似的,都是利用Custom Draw。这里涉及到设置当前选中行为特殊颜色,同时要恢复前一次选中行的颜色,否则就乱了。因此需要记录前一次选中行、当前选中行的行号,相信通过前面的总结,这点并不难实现。然后在当前选中行和前一次选中行之间进行重绘即可。

       示例如下:

[cpp]  view plain copy
  1. void CXXXX::OnNMClickXXXX(NMHDR *pNMHDR, LRESULT *pResult)  
  2. {  
  3.     //…………  
  4.   
  5.     //重绘item,更改背景颜色  
  6.     int nFirst = min(m_itemSel,m_itemForeSel);  
  7.     int nLast = max(m_itemSel,m_itemForeSel);  
  8.     m_listCtrl.RedrawItems(nFirst, nLast);  //在前一次选中的item和当前选中的Item之间进行重绘  
  9.   
  10.     *pResult = 0;  
  11. }  
  12. void CXXXX::OnNMCustomdrawXXXX(NMHDR *pNMHDR, LRESULT *pResult)  
  13. {  
  14.     LPNMLVCUSTOMDRAW pLVCD = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR);  
  15.     *pResult = CDRF_DODEFAULT;  
  16.   
  17.     // First thing - check the draw stage. If it's the control's prepaint  
  18.         // stage, then tell Windows we want messages for every item.  
  19.     if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )  
  20.     {  
  21.              *pResult = CDRF_NOTIFYITEMDRAW;  
  22.     }  
  23.         else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )  
  24.     {  
  25.                 // This is the notification message for an item.   
  26.         //处理,将item改变背景颜色  
  27.         if(m_itemSel == pLVCD->nmcd.dwItemSpec)        
  28.         {   //当前选中的item  
  29.             pLVCD->clrTextBk = RGB(255,0,0);  
  30.         }  
  31.         else if(m_itemForeSel == pLVCD->nmcd.dwItemSpec)  
  32.         {   //前一次选中的item,恢复为白色  
  33.             pLVCD->clrTextBk = RGB(255,255,255);  
  34.         }  
  35.   
  36.                 *pResult = CDRF_DODEFAULT;  
  37.     }  
  38. }  



下篇重点介绍:止拖动表头、让第一列居中显示、设置行高与字体、虚拟列表技术、点击表头时进行归类、向上与向下移动、动态调整大小问题、避免闪烁问题


 6、禁止拖动表头

       重载 OnNotify 消息响应函数,屏蔽两个消息通知码: HDN_BEGINTRACKW  和 HDN_DIVIDERDBLCLICKW 。示例如下:

[cpp]  view plain copy
  1. BOOL CXXXX::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)  
  2. {  
  3.     // TODO: Add your specialized code here and/or call the base class  
  4.     //屏蔽两个消息通知码,使得禁止拖动List表头  
  5.     NMHEADER* pNMHeader = (NMHEADER*)lParam;  
  6.     if(((pNMHeader->hdr.code == HDN_BEGINTRACKW) |   
  7.              (pNMHeader->hdr.code == HDN_DIVIDERDBLCLICKW)))  
  8.     {  
  9.         *pResult = TRUE;  
  10.         return TRUE;  
  11.     }  
  12.   
  13.     return CDialog::OnNotify(wParam, lParam, pResult);  
  14. }  

 7、让第一列居中显示

        在插入列时,我们可以通过 参数nFormat来设置文本居中显示,但是这种设置对于第一列是没有作用的。这时我们可以考虑将我们的内容从第二列开始插入(设置为居中显示)。先插入第一列,然后删除第一列,这样原先的第二列就充当了第一列。


 8、设置行高和字体

        设置CListCtrl的行高没有函数接口,可以通过自绘来实现,但是比较麻烦。有一个比较简单的方法是通过使用一个空白的图像将行撑起来,使其高度发生变化。示例如下:

[cpp]  view plain copy
  1. CImageList m_image;  
  2. m_image.Create(1,24,ILC_COLOR32,1,0);  
  3. m_listInfo.SetImageList(&m_image, LVSIL_SMALL);  
        对于字体的设置,我们可以使用 SetFont 函数来实现。以修改CListView的字体为例,在OnInitialUpdate函数中插入列之前调用SetFontSelf函数(该函数自定义,如下示例所示)。首先创建一个字体,然后调用SetFont进行设置。需要注意的是,在退出时需要delete 掉创建的字体,避免内存泄露。

[cpp]  view plain copy
  1. //设置字体和大小  
  2. void CMyListView::SetFontSelf(int nHeight, LPCTSTR lpszFacename)  
  3. {  
  4.     //先删除原有字体  
  5.     if(m_font != NULL)  
  6.         delete m_font;  
  7.     m_font = new CFont;  
  8.     //创建字体  
  9.     m_font->CreateFont(  
  10.         nHeight,                   // nHeight  
  11.         0,                         // nWidth  
  12.         0,                         // nEscapement  
  13.         0,                         // nOrientation  
  14.         FW_NORMAL,                 // nWeight  
  15.         FALSE,                     // bItalic  
  16.         FALSE,                     // bUnderline  
  17.         0,                         // cStrikeOut  
  18.         ANSI_CHARSET,              // nCharSet  
  19.         OUT_DEFAULT_PRECIS,        // nOutPrecision  
  20.         CLIP_DEFAULT_PRECIS,       // nClipPrecision  
  21.         DEFAULT_QUALITY,           // nQuality  
  22.         DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily  
  23.         lpszFacename);             // lpszFacename  
  24.   
  25.     //设置字体  
  26.     CListCtrl &theCtrl = GetListCtrl();     //获取控制权,引用变量  
  27.     theCtrl.SetFont(m_font, TRUE);  
  28. }  



 9、虚拟列表技术

        给一个链接,介绍的比较详细: http://hi.baidu.com/qi_xian/blog/item/929b04ce27d02c0592457ef8.html

       当数据量大时,使用InsertItem插入数据的过程是很漫长的。这时我们有两个方法来解决该问题:一是使用CListCtrl的虚拟列表技术,二是采用分页显示的方法。对于虚拟列表技术,上述链接中的文章讲的很详细,我用过它的比较简单的方法,后来改用了分页方法。

       使用虚拟列表技术,有三点需要搞清楚:

 使用虚拟技术时,需要将CListCtrl控件的Owner Data属性设置为ture。

 给虚拟列表添加元素时,不需要使用InserItem函数,通过调用SetItemCount设置数据总个数,然后由系统产生不同的消息,在相应的消息响应函数中完成插入工作。

 虚拟列表向父窗口发送的消息有三种: ⑴ 当它需要数据时,发送LVN_GETDISPINFO消息; ⑵ 当用户试图查找某个元素时,发送LVN_ODFINDITEM消息; ⑶当需要缓冲数据时,发送 LVN_ODCACHEHINT消息。    

        当我们使用LVN_GETDISPINFO 的消息处理函数来插入元素时,必须首先检查列表请求的是什么数据(如LVIF_TEXT、LVIF_IMAGE等),然后插入不同的子项。示例如下:

[cpp]  view plain copy
  1. void CDataAnalysis::OnLvnGetdispinfoAnalysisList(NMHDR *pNMHDR, LRESULT *pResult)  
  2. {  
  3.     NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);  
  4.     // TODO: Add your control notification handler code here  
  5.     LV_ITEM* pItem= &(pDispInfo)->item;  
  6.     int iItemIndex= pItem->iItem;  
  7.     size_t converted = 0;  
  8.     wchar_t wStr[30];            //Unicode字符串  
  9.     if (pItem->mask & LVIF_TEXT) //字符串缓冲区有效  
  10.     {  
  11.         switch(pItem->iSubItem)  
  12.         {  
  13.         case 0: //填充数据项的名字,xxxxx表示要填充的字符  
  14.             mbstowcs_s(&converted, wStr, 30, xxxxxx, _TRUNCATE);  
  15.             lstrcpy(pItem->pszText,wStr);  
  16.             break;  
  17.         case 1: //填充子项1  
  18.             mbstowcs_s(&converted, wStr, 30, xxxxxx, _TRUNCATE);  
  19.             lstrcpy(pItem->pszText,wStr);  
  20.             break;  
  21.         case 2: //填充子项2  
  22.             mbstowcs_s(&converted, wStr, 30, xxxxxx, _TRUNCATE);  
  23.             lstrcpy(pItem->pszText,wStr);  
  24.             break;  
  25.         case 3: //填充子项3  
  26.             lstrcpy(pItem->pszText,xxxxxx);  
  27.             break;  
  28.         }  
  29.     }  
  30.   
  31.     *pResult = 0;  
  32. }  



 10、点击表头时进行归类排序

         系统通过发送 LVM_SORTITEMS 消息来处理归类问题,在该消息的处理函数中需要调用一个 回调函数 ,这个回调函数需要我们来设计,以完成不同的归类方法。回调函数原型如下:

                      int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)

          针对上述回调函数,有以下几点需要搞清楚:

 对于参数lparam1和lparam2,分别为CListCtrl的两行数据,是用于比较的对象。通过CListCtrl的成员函数SetItemData来设置,该函数原型:

                     int SetItemData(int nIndex,  DWORD_PTR dwItemData )

其第一个参数为行号,第二个参数指明了该行对应的参数。参数dwItemData 通常设为一行参数的数组,如: pData[2][2] = {{1, 3},{2, 3}}; 每次使用pData[i]作为dwItemData。

 对于参数lParamSort,用于指明列项,即第几列。该参数和回调函数一同通过CListCtrl的成员函数SortItems来设置,其函数原型为:

                    BOOL SortItems( PFNLVCOMPARE pfnCompare,DWORD_PTR dwData )

参数 pfnCompare 为回调函数入口地址, 参数dwData 为列项。

③ SetItemData在初始插入数据时进行调用来设置,SortItems则在点击列表头时响应的消息处理函数中进行设置。

示例如下:

[cpp]  view plain copy
  1. //初始化列表视图控件  
  2. BOOL CDataAnalysis::InitListCtl()  
  3. {  
  4.     //其他处理,包括设置风格,插入列等等  
  5.     //插入行  
  6.     for(int i=0; i<LineNum; i++)  
  7.     {  
  8.         //要将char*转换为wchar_t*  
  9.         mbstowcs_s(&converted, wStr, 30, m_analysis[i].Date, _TRUNCATE);  
  10.         m_listAnalysis.InsertItem(i, wStr);                             //日期  
  11.         mbstowcs_s(&converted, wStr, 30, m_analysis[i].Time, _TRUNCATE);  
  12.         m_listAnalysis.SetItemText(i, 1, wStr);                         //时间  
  13.         mbstowcs_s(&converted, wStr, 30, m_analysis[i].ID, _TRUNCATE);  
  14.         m_listAnalysis.SetItemText(i, 2, wStr);                         //ID  
  15.         m_listAnalysis.SetItemText(i, 3, m_analysis[i].lpszEvent);      //事件  
  16.   
  17.         //设置回调函数的参数  
  18.         m_listAnalysis.SetItemData(i, (LPARAM)(m_analysis+i));  
  19.     }  
  20.   
  21.     return TRUE;  
  22. }  
  23. void CDataAnalysis::OnHdnItemclickAnalysisList(NMHDR *pNMHDR, LRESULT *pResult)  
  24. {  
  25.     LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);  
  26.     // TODO: Add your control notification handler code here  
  27.   
  28.     //设置回调函数的参数和入口地址  
  29.     m_listAnalysis.SortItems(SortFunc, phdr->iItem);  
  30.   
  31.     *pResult = 0;  
  32. }  
  33. //排序的回调函数  
  34. int CALLBACK SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)  
  35. {  
  36.     int result;     //返回值  
  37.   
  38.     //两行的参数,用于比较  
  39.     ANALYSISFORMAT* pAnalysis1 = (ANALYSISFORMAT*)lParam1;  
  40.     ANALYSISFORMAT* pAnalysis2 = (ANALYSISFORMAT*)lParam2;  
  41.   
  42.     //排序  
  43.     switch(lParamSort)  
  44.     {  
  45.     case 0:     //日期  
  46.         result = strcmp(pAnalysis1->Date, pAnalysis2->Date);  
  47.         break;  
  48.     case 1:     //时间  
  49.         result = strcmp(pAnalysis1->Time, pAnalysis2->Time);  
  50.         break;  
  51.     case 2:     //ID  
  52.         result = strcmp(pAnalysis1->ID, pAnalysis2->ID);  
  53.         break;  
  54.     case 3:     //事件  
  55.         result = wcscmp(pAnalysis1->lpszEvent, pAnalysis2->lpszEvent);  
  56.         break;  
  57.     default:  
  58.         break;  
  59.     }  
  60.   
  61.     return result;  
  62. }  

 11、向上与向下移动

        有时需要向上或向下移动表项内容,这里给出向上移动的方法,向下移动的方法类似。

① 利用第2节所述的内容获取行号nItem,判断行号是否为行首,如果不是行首则进入②;

② 获取第nItem行的所有子项内容;

③ 删除第nItem行,并在nItem-1的位置重新插入原先的第nItem行的内容;

④ 使nItem-1的位置高亮显示

示例如下:

[cpp]  view plain copy
  1. /*************************上移子项**************************/  
  2. void CStudyTestDlg::OnPageup()   
  3. {  
  4.     if (nItem == 0)  
  5.     {  
  6.         MessageBox("该子项已经位于第一行!");  
  7.         return;  
  8.     }  
  9.   
  10.     // 提取内容  
  11.     CString temp[4];  
  12.     int i;  
  13.     for(i=0;i<4;i++)  
  14.         temp[i] = m_ListCtrl.GetItemText(nItem, i);  
  15.   
  16.     // 删除  
  17.     m_ListCtrl.DeleteItem(nItem);  
  18.   
  19.     // 在nItem-1位置处插入  
  20.     for (i=0; i<4; i++)  
  21.         m_ListCtrl.SetItemText(nItem-1,i,temp[i]);  
  22.   
  23.     //高亮显示  
  24.     UINT flag = LVIS_SELECTED|LVIS_FOCUSED;  
  25.     m_ListCtrl.SetItemState(--nItem, flag, flag);  
  26. }  
  27.   
  28. /*************************下移子项**************************/  
  29. void CStudyTestDlg::OnPagedown()   
  30. {  
  31.     if (nItem == m_ListCtrl.GetItemCount()-1)  
  32.     {  
  33.         MessageBox("该子项已经位于最后一行!");  
  34.         return;  
  35.     }  
  36.   
  37.     // 提取内容  
  38.     CString temp[4];  
  39.     int i;  
  40.     for (i=0; i<4; i++)  
  41.         temp[i] = m_ListCtrl.GetItemText(nItem, i);  
  42.   
  43.     // 删除  
  44.     m_ListCtrl.DeleteItem(nItem);  
  45.   
  46.     // 在nItem+1位置处插入  
  47.     for (i=0; i<4; i++)  
  48.         m_ListCtrl.SetItemText(nItem+1, i,temp[i]);  
  49.   
  50.     //高亮显示  
  51.     UINT flag = LVIS_SELECTED|LVIS_FOCUSED;  
  52.     m_ListCtrl.SetItemState(++nItem, flag, flag);  
  53. }  

 12、避免闪烁问题

           这个问题在我的前面一篇博文有提到。

  http://blog.csdn.net/zwgdft/article/details/7394318

 

13、动态调整大小

        有时由于不确定软件运行时的电脑屏幕大小,需要根据屏幕大小动态设置CListCtrl控件的大小。动态大小的设置时,需要注意不要将高度和宽度设置的超过区域限制,否则就没有滚动条了,导致部分内容无法查看。以我遇到的一个例子来说,其情况见第12节提到的那篇博文所述:将View划分为三个窗格,在左上角View上有个CPropertySheet,其上有几个CPropertyPage,每个属性页上有个CListCtrl,供用户查看信息。那么这时需要设置的CListCtrl的大小即为:

                                              宽度 = 左上角View宽度

                                              高度 = 左上角View高度 - 属性页的Tab项高度

调用MoveWindow函数进行设置即可。


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值