MFC常用控件之列表视图控件(List Control)

近期学习了鸡啄米大神的博客,对其中的一些知识点做了一些自己的总结。不过,博客内容大部分来自鸡啄米。因此,这个博客算是转载博客,只是加了一些我自己的理解而已。若想学习鸡啄米大神的博客总结,请点击连接:http://www.jizhuomi.com/software/257.html

1.List Control控件:列表视图控件的列表项一般有图标(Icon)和标签(Label)两部分。图标是对列表项的图形描述,标签是文字描述。当然列表项可以只包含图标也可以只包含标签。

2.列表视图控件有4种风格:Icon、Small Icon、List和Report。下面简单说下4种风格各自的特点:
    Icon大图标风格:列表项的图标通常为32×32像素,在图标的下面显示标签。
    Small Icon小图标风格:列表项的图标通常为16×16像素,在图标的右面显示标签。
    List列表风格:与小图标风格类似,图标和文字的对齐方式不同。
    Report报表风格:列表视图控件可以包含一个列表头来描述各列的含义。每行显示一个列表项,通常可以包含多个列表子项。最左边的列表子项的标签左边可以添加一个图标,而它右边的所有子项则只能显示文字。这种风格的列表视图控件很适合做各种报表。

3.相关消息:
(1)NM_CLICK的通知消息:在该消息的消息处理函数中的第一句有这样一句系统为我们加上的代码:     
    LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
通过这句代码我们可以看出:上面的代码中将NMHDR指针类型的pNMHDR强制转换为LPNMITEMACTIVATE类型的pNMItemActivate,那么我们就可以在函数中通过pNMHDR来访问NMHDR结构,也可以通过pNMItemActive指针变量来访问第一个元素为NMHDR结构体变量的扩充结构。
(2)LVN_ITEMCHANGING 和LVN_ITEMCHANGED:当列表视图的状态发生变化时,会发送这两个通知消息。例如,当用户选择了新的列表项时,程序就会收到这两个消息。消息会附带一个指向NMLISTVIEW 结构的指针,消息处理函数可从该结构中获得状态信息。两个消息的不同之处在于,前者的消息处理函数如果返回TRUE,那么就阻止选择的改变,如果返回FALSE,则允许改变。
(3)LVN_KEYDOWN:该消息表明了一个键盘事件。消息会附带一个指向NMLVKEYDOWN结构的指针,通过该结构程序可以获得按键的信息。
(4)LVN_BEGINLABELEDIT 和LVN_ENDLABELEDIT:分别在用户开始编辑和结束编辑标题时发送。消息会附带一个指向NMLVDISPINFO结构的指针。在前者的消息处理函数中,可以调用GetEditControl成员函数返回一个指向用于编辑标题的编辑框的指针,如果处理函数返回FALSE,则允许编辑,如果返回TRUE,则禁止编辑。在后者的消息处理函数中,NMLVDISPINFO结构中的item.pszText指向编辑后的新标题,如果pszText 为NULL,那么说明用户放弃了编辑,否则,程序应负责更新表项的标题,这可以由SetItem或SetItemText函数来完成。

4.列表视图控件相关结构体:
.列表视图控件相关结构体:

typedef struct tagNMHDR {   
    HWND hwndFrom;     // 控件窗口的句柄   
     UINT_PTR idFrom;   // 控件ID   
    UINT code;         // 控件的通知消息码   
} NMHDR;

 此结构体在很多情况下都是其他扩充结构体的第一个元素,比如上面的NMITEMACTIVATE结构体:

typedef struct tagNMITEMACTIVATE {   
    NMHDR hdr;   
    int iItem;   
    int iSubItem;   
    UINT uNewState;   
    UINT uOldState;   
    UINT uChanged;   
    POINT ptAction;   
    LPARAM lParam;   
    UINT uKeyFlags;   
} NMITEMACTIVATE, *LPNMITEMACTIVATE;

 LVITEM结构体:该结构体包含了列表视图控件中列表项或列表子项的各种属性。

    typedef struct _LVITEM {    
        UINT mask;           // 掩码位的组合(下面有对应掩码的元素都已在括号中标出掩码),表明哪些元素是有效的   
        int iItem;           // 列表项的索引   
        int iSubItem;        // 列表子项的索引   
        UINT state;          // 状态,下面会列出。(LVIF_STATE)   
        UINT stateMask;      // 状态掩码,用来说明要获取或设置哪些状态。下面会列出   
        LPTSTR pszText;      // 指向列表项或列表子项的标签字符串。(LVIF_TEXT)   
        int cchTextMax;      // pszText指向缓冲区的字符的个数,包括字符串结束符。(LVIF_TEXT)   
        int iImage;          // 图标的索引。(LVIF_IMAGE)   
        LPARAM lParam;       // 32位的附加数据。(LVIF_PARAM)   
    #if (_WIN32_IE >= 0x0300)   
        int iIndent;   
    #endif   
    #if (_WIN32_WINNT >= 0x501)   
        int iGroupId;   
        UINT cColumns; // tile view columns   
        PUINT puColumns;   
    #endif   
    #if (_WIN32_WINNT >= 0x0600)   
        int* piColFmt;   
        int iGroup;   
    #endif   
    } LVITEM, *LPLVITEM;  

 下面是state和stateMask的取值及含义:

 状态                     对应的状态掩码                   含义
        LVIS_CUT                     同左                 列表项或列表子项被选择用来进行剪切和粘贴操作
        LVIS_DROPHILITED      同左                 列表项或列表子项成为拖动操作的目标
        LVIS_FOCUSED            同左                 列表项或列表子项具有输入焦点
        LVIS_SELECTED           同左                 列表项或列表子项被选中

LVCOLUMN结构体:该结构体仅适用于Report报表式列表视图控件。在向列表控件中插入一列时需要用到此结构体。它包含了列表控件某列的各种属性

    typedef struct _LVCOLUMN {    
        UINT mask;              // 掩码位的组合(下面有对应掩码的元素都已在括号中标出掩码),表明哪些元素是有效的   
        int fmt;                    // 该列的表头和列表子项的标签正文显示格式,可以是LVCFMT_CENTER、LVCFMT_LEFT或LVCFMT_RIGHT。(LVCF_FMT)   
        int cx;                     // 以像素为单位的列的宽度。(LVCF_FMT)   
        LPTSTR pszText;    // 指向列表头标题正文的字符串。(LVCF_TEXT)   
        int cchTextMax;     // pszText指向缓冲区的字符的个数,包括字符串结束符。(LVCF_TEXT)   
        int iSubItem;          // 该列的索引。(LVCF_SUBITEM)   
    #if (_WIN32_IE >= 0x0300)   
        int iImage;   
        int iOrder;   
    #endif   
    #if (_WIN32_WINNT >= 0x0600)   
        int cxMin;   
        int cxDefault;   
        int cxIdeal;   
    #endif   
    } LVCOLUMN, *LPLVCOLUMN;  

 NMLISTITEM结构体:该结构体存放了列表视图控件通知消息的相关信息。列表视图控件的大部分通知消息都会附带指向该结构体的指针。

    typedef struct tagNMLISTVIEW {   
        NMHDR hdr;       // 标准的NMHDR 结构   
         int iItem;       // 列表项的索引   
         int iSubItem;    // 列表子项的索引   
         UINT uNewState;  // 列表项或列表子项的新状态   
         UINT uOldState;  // 列表项或列表子项原来的状态   
         UINT uChanged;   // 取值与LVITEM的mask成员相同,用来表明哪些状态发生了变化   
         POINT ptAction;  // 事件发生时鼠标的客户区坐标   
         LPARAM lParam;   //32位的附加数据   
    } NMLISTVIEW, *LPNMLISTVIEW;  

5.列表视图控件类:CListCtrl类:

6.创建列表视图控件:
virtual BOOL Create(
   DWORD dwStyle,
   const RECT& rect,
   CWnd* pParentWnd,
   UINT nID
);
针对dwStyle参数进行说明:
       风格                                                含义
       LVS_ALIGNLEFT                        显示格式是大图标或小图标时,标签放在图标的左边
       LVS_ALIGNTOP                         显示格式是大图标或小图标时,标题放在图标的上边
       LVS_AUTOARRANGE                      显示格式是大图标或小图标时,自动排列控件中的列表项
       LVS_EDITLABELS                       用户可以修改标签文本
       LVS_ICON                             指定大图标显示格式
       LVS_LIST                             指定列表显示格式
       LVS_NOCOLUMNHEADER                   在报表格式中不显示列的表头
       LVS_NOLABELWRAP                      显示格式是大图标时,使标签文本单行显示。默认是多行显示
       LVS_NOSCROLL                         列表视图控件无滚动条,此风格不能与LVS_LIST或LVS_REPORT组合使用
       LVS_NOSORTHEADER                     报表格式的列表视图控件的表头不能作为排序按钮使用
       LVS_OWNERDRAWFIXED                   由控件的拥有者负责绘制表项
       LVS_REPORT                           指定报表显示格式
       LVS_SHAREIMAGELISTS                  使列表视图共享图像序列
       LVS_SHOWSELALWAYS                    即使控件失去输入焦点,仍显示出项的选择状态
       LVS_SINGLESEL                        指定只能有一个列表项被选中。默认时可以多项选择
       LVS_SMALLICON                        指定小图标显示格式
       LVS_SORTASCENDING            按升序排列列表项
       LVS_SORTDESCENDING            按降序排列列表项

7.获取被选择列表项行数: UINT GetSelectedCount( ) const;

8.获取第一个被选择项的位置:POSITION GetFirstSelectedItemPosition( ) const;
返回的POSITION值可以用来迭代来获取其他选择项,可以当作参数传入下面的GetNextSelectedItem函数来获得选择项的索引。如果没有被选择项则返回NULL。

9.int GetNextSelectedItem(POSITION& pos) const;
该函数获取由pos指定的列表项的索引,然后将pos设置为下一个位置的POSITION值。返回值就是pos指定列表项的索引。

10.获取列表项数量:int GetItemCount( ) const;

11.插入列:
int InsertColumn(int nCol,const LVCOLUMN* pColumn );
int InsertColumn(int nCol,LPCTSTR lpszColumnHeading,int nFormat = LVCFMT_LEFT,int nWidth = -1,int nSubItem = -1 );
这两个函数用于在报表式列表视图控件中插入列。第一个函数中,nCol参数为插入列的索引,pColumn参数指向LVCOLUMN结构,其中包含了插入列的属性。第二个函数中,lpszColumnHeading参数为列标题字符串,nFormat参数为列中文本的对齐方式,可以是LVCFMT_LEFT、LVCFMT_RIGHT或LVCFMT_CENTER,nWidth参数为列宽,nSubItem为插入列对应列表子项的索引。两个函数在成功时都返回新列的索引,失败都返回-1。

12.删除某列:BOOL DeleteColumn(int nCol);

13.插入新的列表项:int InsertItem(int nItem,LPCTSTR lpszItem);

14.删除某行:BOOL DeleteItem(int row);nItem指定了要删除的行的索引

15.获取指定列表项或列表子项的显示文本。
    CString GetItemText(int row,int colomn) const;

16.设置指定列表项或列表子项的显示文本:
BOOL SetItemText(int row,int column,LPCTSTR lpszText);

17.获取指定列表项的附加32位数据:
DWORD_PTR GetItemData(int nItem) const;

18.设置指定列表项的附加32位数据:
 BOOL SetItemData(int nItem,DWORD_PTR dwData)

示例代码:

 1 插入数据,设置属性:
 2 //列表视图控件
 3     CRect rect;
 4     m_listCtrl.GetClientRect(&rect);
 5     m_listCtrl.SetExtendedStyle(m_listCtrl.GetExtendedStyle()|LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
 6 
 7     m_listCtrl.InsertColumn(0,"语言",LVCFMT_CENTER,rect.Width()/3,0);
 8     m_listCtrl.InsertColumn(1,"2016排名",LVCFMT_CENTER,rect.Width()/3,1);
 9     m_listCtrl.InsertColumn(2,"2017排名",LVCFMT_CENTER,rect.Width()/3,2);
10 
11     m_listCtrl.InsertItem(0,"java");
12     m_listCtrl.SetItemText(0,1,"1");
13     m_listCtrl.SetItemText(0,2,"1");
14 
15     m_listCtrl.InsertItem(1,"c++");
16     m_listCtrl.SetItemText(1,1,"2");
17     m_listCtrl.SetItemText(1,2,"2");
18 
19     m_listCtrl.InsertItem(2,"c#");
20     m_listCtrl.SetItemText(2,1,"5");
21     m_listCtrl.SetItemText(2,2,"3");
22 
23 消息处理函数:
24 void CMFC_NoramlControlDlg::OnNMClickList1(NMHDR *pNMHDR, LRESULT *pResult)
25 {
26 //    LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<NMITEMACTIVATE>(pNMHDR);
27     // TODO: Add your control notification handler code here
28     *pResult = 0;
29 
30     CString strLanguageName;
31     NMLISTVIEW* pNmListView=(NMLISTVIEW*)pNMHDR;
32     if (pNmListView->iItem!=-1)
33     {
34         strLanguageName=m_listCtrl.GetItemText(pNmListView->iItem,0);
35         AfxMessageBox(strLanguageName);
36     }
37 }
View Code