list control


   

【前话】

    编译原理的第一个实验——词法分析器验收时,老师要求最后的结果用GUI的形式表现出来。想想确实,黑白的控制台应用程序界面在用户操作时的确不如GUI 友好。GUI界面也算是大势所趋。我现在掌握三种语言的基本语法——c/c++、Java和python。python好久之前学过然后没用就忘记了,最近想写网络爬虫才又重新去看,对于python写GUI也是一窍不通,不做考虑。自认为Java写GUI比较方便,但是实验代码已经用c写完了,所以最后 决定用mfc做这个GUI。

    到了大二下陆陆续续的做了一些mfc,每次用一个新控件都是网上各种找然后XJBG一下就完成了。每次要用的时候又要找,所以打算每学习一个控件就就写个随笔系统地记录一下使用方法和心得。

    废话不说,下面上list control的用法。

【list control】

    在console中可以用#include<iomanip>的setw()来设置输出的格式,原本认为mfc里的控件edit control里也这样输出一下就可以了,结果做出来的效果是这样的:

    看来用setw()方法不能得到想要的效果,而且edit control里的文本可以随意更改,所以想找一个类似列表的控件作为输出显示。

    最后得到这样的效果,就要用到今天要介绍的list control。

    拖到对话框后的显示是这样的:

    选中控件,修改将外观中的View项从Icon改为Report,再调整大小。

    然后右键->类向导->成员变量,设置如下图:

    接下来在CProjectNameDlg.cpp文件的OnInitDialog()函数中初始化list的列属性并进行设置:

        DWORD dwStyle = m_list.GetExtendedStyle();     
        dwStyle |= LVS_EX_FULLROWSELECT;
        dwStyle |= LVS_EX_GRIDLINES;
        m_list.SetExtendedStyle(dwStyle);

    第一句得到m_list的风格。

    LVS_EX_FULLROWSELECT为整行选中,当鼠标点击某个单元式那一整行都选中。

    LVS_EX_GRIDLINES为添加网格线。

    第四句将我们配置的风格添加到m_list。

    接下去设置每列的属性:

        m_list.InsertColumn(0, _T(" "), LVCFMT_LEFT, 25);
        m_list.InsertColumn(1, _T("单词"), LVCFMT_LEFT, 60);
        m_list.InsertColumn(2, _T("二元序列"), LVCFMT_LEFT, 80);
        m_list.InsertColumn(3, _T("类型"), LVCFMT_LEFT, 80);
        m_list.InsertColumn(4, _T("位置(行,列)"), LVCFMT_LEFT, 100); 

 

    我按照自己的理解来说下函数的用法。InsertColumn(设置的列是第几列,列的属性名,属性名的格式,列宽)。
    然后就是在触发某个控件后在list control中显示。这里触发可以是按了某个按钮或者读入了某个文件Balabala...

        m_list.InsertItem(n, CStr1);
        m_list.SetItemText(n, 1, CStr2);
        m_list.SetItemText(n, 2, CStr3);
        m_list.SetItemText(n, 3, CStr4);
        m_list.SetItemText(n, 4, CStr5); 

 

    InsertItem(n, CStr)  是将CStr加入第n行第0列。这里n也是从0开始计的。
    SetItemText(n, line, CStr)  是在第n行第line列加入CStr。但是如果用SetItemText加入第0列的元素是没效果的

    我的理解是先用InsertItem()申请了一行的list可用,后面的才可以用SetItemText()加入。

    两个函数插入list中的元素必须是CString类型。我一般都是把所有东西转化成string,然后用CString CStr(string.c_str())来解决的。。。

   然后CY告诉我一个很好用的东西:stringstream。以后用的多了也写篇随笔总结下好了。

   最后是list control的清空方法:m_list.DeleteAllItems()。



我用了一个基于对话框的MFC程序进行测试。
第一步:创建基于对话框的MFC应用程序
第二步:在对话框上添加一个List Control控件
第三步:给ListControl控件绑定一个ListControl类型的控件变量:m_List
第四步:给对话框上的ListControl控件添加NM_CUSTOMDRAW事件的消息处理函数OnNMCustomdrawList1
代码如下:
void CTestListCtrlDlg::OnNMCustomdrawList1(NMHDR *pNMHDR, LRESULT *pResult)
{
        LPNMLVCUSTOMDRAW pLVCD = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR);
        *pResult = CDRF_DODEFAULT;
        // TODO: 在此添加控件通知处理程序代码
        COLORREF crText;
        if (CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage)
        {        
                *pResult = CDRF_NOTIFYITEMDRAW;   
        }   
        else if (CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage)
        {                       
                if ( (pLVCD->nmcd.dwItemSpec % 3) == 0)            
                {
                        crText = RGB(255,0,0);        
                }
                else if((pLVCD->nmcd.dwItemSpec % 3) == 1)
                {
                        crText = RGB(0,255,0);
                }                        
                else  
                {
                        crText = RGB(128,128,255);
                }
                pLVCD->clrText = crText;
                *pResult = CDRF_DODEFAULT;       
                      }               
}
这里注意的一点就是这句代码:*pResult = CDRF_DODEFAULT;,一定要写在else if 语句的最后,我当时由于马虎,把这句写在了这个函数的最后,就是else if 语句后面了,导致ListControl控件里的颜色没有发生变化,害了我在网上查了两个小时,





1. CListCtrl 样式及设置

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. LVS_ICON: 每个item显示大图标  
  2. LVS_SMALLICON: 每个item显示小图标  
  3. LVS_LIST: 显示一列带有小图标的item  
  4. LVS_REPORT: 显示item详细资料  
  5. 如windows资源管理器,“查看”标签下的“大图标,小图标,列表,详细资料”  
  6. LONG lStyle;  
  7. lStyle=GetWindowLong(m_ListCtrl.m_hWnd, GWL_STYLE); //获取当前窗口style  
  8. lStyle &= ~LVS_TYPEMASK; //清除显示方式位  
  9. lStyle |= LVS_REPORT; //设置style  
  10. SetWindowLong(m_ListCtrl.m_hWnd, GWL_STYLE, lStyle); //设置style  

2. 扩展样式设置

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. DWORD dwStyle = m_ListCtrl.GetExtendedStyle(); //获取当前扩展样式  
  2. dwStyle |= LVS_EX_FULLROWSELECT; //选中某行使整行高亮(report风格时)  
  3. dwStyle |= LVS_EX_GRIDLINES; //网格线(report风格时)  
  4. dwStyle |= LVS_EX_CHECKBOXES; //item前生成checkbox控件  
  5. m_ListCtrl.SetExtendedStyle(dwStyle); //设置扩展风格  

3. 数据插入

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. m_ListCtrl.InsertColumn(0,"名称",LVCFMT_LEFT,50); //插入列  
  2. m_ListCtrl.InsertColumn(1,"备注",LVCFMT_LEFT,50);  
  3. //直接插入:  
  4. int nRow=m_ListCtrl.InsertItem(0, "VC++");        //插入行  
  5. m_ListCtrl.SetItemText(nRow,1,"Visual C++ 6.0");  //设置数据  
  6. //LVITEM 结构插入:  
  7. LVITEM item={0};  
  8. item.iItem=0;  //行号  
  9. item.mask=LVIF_TEXT; /*LVIF_IMAGE支持图标*/;  
  10. item.cchTextMax=15;//插入字符串长度  
  11. item.pszText="Visual C++ 6.0";  
  12. int nRow=m_ListCtrl.InsertItem(&item);  
  13. m_ListCtrl.SetItemText(nRow,1,"Visual C++ 6.0");  

4. 一直选中Item

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 选中style中的 Show selection always,  
  2. 或者添加扩展样式 LVS_SHOWSELALWAYS  

5. 选中和取消选中Item

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int nIndex = 0;  
  2. //选中  
  3.  m_ListCtrl.SetItemState(nIndex,LVIS_SELECTED|  
  4.  LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED);  
  5. //取消选中  
  6.  m_ListCtrl.SetItemState(nIndex,0,LVIS_SELECTED|LVIS_FOCUSED);  

6. 得到CListCtrl中所有行的checkbox的状态

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. CString str;  
  2. for(int i=0; i<m_ListCtrl.GetItemCount(); i++)  
  3. {  
  4.   if(m_ListCtrl.GetItemState(i, LVIS_SELECTED)==  
  5.    LVIS_SELECTED || m_ListCtrl.GetCheck(i))  
  6.   {  
  7.     str.Format(_T("第%d行的checkbox为选中状态"), i);  
  8.     AfxMessageBox(str);  
  9.    }  
  10.  }  

7. 得到CListCtrl中所有选中行的序号

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //方法一:  
  2.  CString str;  
  3.  for(int i=0; i<m_ListCtrl.GetItemCount(); i++)  
  4.  {  
  5.    if(m_ListCtrl.GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED )  
  6.    {  
  7.      str.Format(_T("选中了第%d行"), i);  
  8.      AfxMessageBox(str);  
  9.     }  
  10.   }  
  11. //方法二:  
  12.  POSITION pos=m_ListCtrl.GetFirstSelectedItemPosition();  
  13.  if(pos==NULL)  
  14.   TRACE0("No items were selected!/n");  
  15.  else  
  16.  {  
  17.   while(pos)  
  18.    {  
  19.      int nItem=m_ListCtrl.GetNextSelectedItem(pos);  
  20.      TRACE1("Item %d was selected!/n", nItem);  
  21.      //添加其他操作  
  22.     }  
  23.   }  

8. 得到item的信息

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. TCHAR szBuf[1024];  
  2. LVITEM lvi;  
  3. lvi.iItem = nItemIndex;  
  4. lvi.iSubItem = 0;  
  5. lvi.mask = LVIF_TEXT;  
  6. lvi.pszText = szBuf;  
  7. lvi.cchTextMax = 1024;  
  8. m_ListCtrl.GetItem(&lvi);  

9. 得到CListCtrl的所有列的header字符串内容

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. LVCOLUMN lvcol;  
  2. char  str[256];  
  3. int   nColNum;  
  4. CString strColumnName[3];//假如有3列  
  5. nColNum = 0;  
  6. lvcol.mask = LVCF_TEXT;  
  7. lvcol.pszText = str;  
  8. lvcol.cchTextMax = 256;  
  9. while(m_list.GetColumn(nColNum, &lvcol))  
  10. {   
  11.   strColumnName[nColNum] = lvcol.pszText;  
  12.   nColNum++;  
  13.  }  

10. 使CListCtrl中一项可见,即滚动滚动条

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. m_ListCtrl.EnsureVisible(i, FALSE);  

11. 得到CListCtrl列数

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. int nHeadNum=m_ListCtrl.GetHeaderCtrl()->GetItemCount();  

12. 删除所有列

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 方法一:  
  2.  while(m_ListCtrl.DeleteColumn(0))  
  3.  //因为你删除了第一列后,后面的列会依次向上移动。  
  4. 方法二:  
  5.  int nColumns = 3; //列数  
  6.  for(int i=nColumns-1; i>=0; i--)  
  7.   m_ListCtrl.DeleteColumn(i);  

13. 得到单击的CListCtrl的行列号

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 添加listctrl控件的NM_CLICK消息相应函数  
  2. void CMyDlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult)  
  3. {  
  4.  //方法一:  
  5.  DWORD dwPos=GetMessagePos();  
  6.  CPoint point( LOWORD(dwPos), HIWORD(dwPos));  
  7.  m_ListCtrl.ScreenToClient(&point);  
  8.  LVHITTESTINFO lvinfo;  
  9.  lvinfo.pt=point;  
  10.  lvinfo.flags=LVHT_ABOVE;  
  11.  int nItem=m_ListCtrl.SubItemHitTest(&lvinfo);  
  12.  if(nItem!=-1)  
  13.  {  
  14.    CString strtemp;  
  15.    strtemp.Format("单击的是第%d行第%d列",  
  16.    lvinfo.iItem, lvinfo.iSubItem);  
  17.    AfxMessageBox(strtemp);  
  18.   }  
  19.  // 方法二:  
  20.  NM_LISTVIEW* pNMListView=(NM_LISTVIEW*)pNMHDR;  
  21.  if(pNMListView->iItem!=-1)  
  22.  {  
  23.    CString strtemp;  
  24.    strtemp.Format("单击的是第%d行第%d列",  
  25.    pNMListView->iItem, pNMListView->iSubItem);  
  26.    AfxMessageBox(strtemp);  
  27.   }  
  28.   *pResult = 0;  
  29. }  

14. 判断是否点击在CListCtrl的checkbox上

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 添加listctrl控件的NM_CLICK消息相应函数  
  2. void CMyDlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult)  
  3. {  
  4.   DWORD dwPos=GetMessagePos();  
  5.   CPoint point(LOWORD(dwPos), HIWORD(dwPos));  
  6.   m_ListCtrl.ScreenToClient(&point);  
  7.   LVHITTESTINFO lvinfo;  
  8.   lvinfo.pt=point;  
  9.   lvinfo.flags=LVHT_ABOVE;  
  10.   UINT nFlag;  
  11.   int nItem=m_ListCtrl.HitTest(point, &nFlag);  
  12.   //判断是否点在checkbox上  
  13.   if(nFlag==LVHT_ONITEMSTATEICON)  
  14.   {  
  15.     AfxMessageBox("点在listctrl的checkbox上");  
  16.   }   
  17.   *pResult = 0;  
  18. }  

15. 右键点击CListCtrl的item弹出菜单

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 添加CListCtrl控件的NM_RCLICK消息相应函数  
  2. void CMyDlg::OnRclickList1(NMHDR* pNMHDR, LRESULT* pResult)  
  3. {  
  4.   NM_LISTVIEW* pNMListView=(NM_LISTVIEW*)pNMHDR;  
  5.   if(pNMListView->iItem!=-1)  
  6.   {  
  7.     DWORD dwPos = GetMessagePos();  
  8.     CPoint point( LOWORD(dwPos), HIWORD(dwPos) );  
  9.     CMenu menu;  
  10.     VERIFY( menu.LoadMenu( IDR_MENU1 ) );  
  11.     CMenu* popup = menu.GetSubMenu(0);  
  12.     ASSERT( popup != NULL );  
  13.     popup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,  
  14.     point.x, point.y, this );  
  15.    }   
  16.    *pResult = 0;  
  17. }  

16. CListCtrl进行大数据量更新时,避免闪烁

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. m_ListCtrl.SetRedraw(FALSE);  
  2. //更新内容  
  3. m_ListCtrl.SetRedraw(TRUE);  
  4. m_ListCtrl.Invalidate();  
  5. m_ListCtrl.UpdateWindow();  

 //或者参考  地址

17.举例

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. BOOL CImageDlg::OnInitDialog()  
  2. {  
  3.     CDialog::OnInitDialog();  
  4.     // Add "About..." menu item to system menu.  
  5.     // IDM_ABOUTBOX must be in the system command range.  
  6.     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);  
  7.     ASSERT(IDM_ABOUTBOX < 0xF000);  
  8.     CMenu* pSysMenu = GetSystemMenu(FALSE);  
  9.     if (pSysMenu != NULL)  
  10.   {  
  11.     CString strAboutMenu;  
  12.     strAboutMenu.LoadString(IDS_ABOUTBOX);  
  13.     if (!strAboutMenu.IsEmpty())  
  14.     {  
  15.     pSysMenu->AppendMenu(MF_SEPARATOR);  
  16.     pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);  
  17.      }  
  18.    }  
  19.     DWORD dwStyle = m_list.GetExtendedStyle(); //获取当前扩展样式  
  20.     dwStyle |= LVS_EX_FULLROWSELECT; //选中某行使整行高亮(report风格时)  
  21.     dwStyle |= LVS_EX_GRIDLINES; //网格线(report风格时)  
  22.     m_list.SetExtendedStyle(dwStyle); //设置扩展风格  
  23.     m_list.InsertColumn(0,"ID");  
  24.     m_list.InsertColumn(1,"位置(X)");  
  25.     m_list.InsertColumn(2,"位置(Y)");  
  26.     m_list.InsertColumn(3,"旋转角度(Angle)");  
  27.     m_list.InsertColumn(4,"匹配分数(Score)");  
  28.     CRect rect;  
  29.     m_list.GetClientRect(rect);  
  30.     m_list.SetColumnWidth(0,rect.Width()/5);  
  31.     m_list.SetColumnWidth(1,rect.Width()/5);  
  32.     m_list.SetColumnWidth(2,rect.Width()/5);  
  33.     m_list.SetColumnWidth(3,rect.Width()/5);  
  34.     m_list.SetColumnWidth(4,rect.Width()/5);</span>  
  35.     // Set the icon for this dialog.  The framework does this automatically  
  36.     //  when the application's main window is not a dialog  
  37.     SetIcon(m_hIcon, TRUE);// Set big icon  
  38.     SetIcon(m_hIcon, FALSE);// Set small icon  
  39.     // TODO: Add extra initialization here  
  40.     return TRUE;  // return TRUE  unless you set the focus to a control  
  41. }