1. 列表视图简介:
1) 最常见的列表视图案例就是Windows的资源管理器的右侧视图,就是使用列表视图来展示当前路径下的文件集合的;
2) 列表视图有两大元素,一是文本,而是图形,和树形视图一样,但是这两种元素的展示形式会根据列表视图的样式发生改变;
3) Windows支持的4中列表视图的样式:
i. 小图标:
ii. 大图标:
iii. 列表:
iv. 报表(详细):
4) 在小图标、大图标和列表三种样式中,每个图标文字组合都是一个项目,而在报表模式中除了顶上的标题栏之外,其它每一行都是一个项目,其中最左列是主项目,右侧的列是主项目的子项目,像这里Lecture1.ppt就是主项目,Size的4372480和Last Modified的9/18/15(8:04a)这两项是Lecture1.ppt的子项目,这回在编程中具体体现出来;
5) 列表视图类是CListView,它继承自列表控件CListCtrl,并派生出了大部分功能,在列表视图中要使用列表的有关功能就必须调用CListView的GetListCtrl获得视图内部的列表空间的引用:CListCtrl& CListView::GetListCtrl() const;
2. 列表视图的初始样式:
1) 初始化列表视图时必须要覆盖CListView::PreCreateWindow函数,并设置cs.style来给出列表视图的默认样式;
2) 下表给出里列表视图的通用样式,其它没给出的一些样式是应用在Explorer浏览器中,这里就先不做说明:
i. 所有样式的前缀都是LVS_,即List View Style的缩写,即列表视图样式;
ii. 首先是四种显示模式:
LVS_ICON:大图标模式
LVS_SMLLICON:小图标模式
LVS_LIST:列表样式
LVS_REPORT:报表样式
iii. 项目对其方式:下列3中样式都只在大图标和小图标模式下有效
LVS_ALIGNLEFT:项目沿左边框对齐
LVS_ALIGNTOP:沿顶边框对齐
LVS_ALIGNARRANGE:自动按行和列排列项目
iv. 项目排序:
LVS_SORTASCENDING:按照项目文本字符升序排列
LVS_SORTDESCENDING:降序
v. 和标头有关:只在报表模式下有效,因为只有报表模式会有标头
LVS_NOCOLUMNHEADER:删除标头控件
LVS_NOSORTHEADER:通常用鼠标点击标头的某一项(就会发送LVN_COLUMNCLICK通知),那么该项所表示的列就会按照自定义的规则进行排序,现在该样式将禁止LVN_COLUMNCLICK通知的发送
vi. 功能性样式:
LVS_NOSCROLL:滚动失效,默认下是开启滚动的
LVS_SINGLESEL:限制为单选,禁止多选,默认下是开启多选的
LVS_SHOWSELALWAYS:被选中项目始终加亮,默认下加亮效果在视图失去焦点时消失
LVS_SHAREIMAGELIST:指定图形列表和视图时共享的,而不是绑定的,如果为绑定,那么视图被删除是图形列表也会删除
LVS_EDITLABELS:是项目文本可以直接编辑
LVS_OWNERDRAWFIXED:响应WM_DRAWITEM,可以让控件所有者自行绘制项目文本,即自定义项目内容;
3. 列表视图创建的大致步骤:
1) 首先肯定是现在CListView::PreCreateWindow中设置列表视图的默认样式;
2) 接下来的步骤应该都放在CListView::OnInitialUpdate虚函数中;
3) 首先是使用CImageList::Create分别创建两个图形列表,一个用于大图标模式的大图标列表,另一个是用于小图标、列表、报表模式的小图标列表;
4) 接下来使用CListCtrl的SetImageList将图形列表和列表视图绑定起来:
i. 函数原型:CImageList* CListCtrl::SetImageList(CImageList* pImageList, int nImageListType);
ii. 返回值还是上一次绑定的图形列表;
iii. nImageListType表示该图形列表的图形,在CListCtrl中只有两种类型,一种LVSIL_NORMAL(即大图标列表),另一种是LVSIL_SMALL(即小图标列表),LVSIL_前缀为List View Set Image List的缩写;
!!当使用设置模式的函数将列表视图设置为大图标模式时,列表视图就会自动调用大图标列表里的图标,如果设置为小图标、列表和报表模式,那么就会自动调用小图标列表里的图标;
5) 接下来添加列(即标头),但不过不是只有报表模式有列(标头)的吗?但不过没关系,因为标头只有在报表模式下才会显示,在其它模式下不显示而已,并且后面各个项也可以添加子项,只不过只有在报表模式下才会显示子项而已:
i. 添加列使用CListCtrl的InsertColumn:
int CListCtrl::InsertColumn( int nCol, // 列的索引(从0开始,从左往右) LPCTSTR lpszColumnHeading, // 列标头的内容 int nFormat = LVCFMT_LEFT, // 列标头的对齐方式 int nWidth = –1, // 列的宽度,以像素为单位,-1表示这是一个空列 int nSubItem = –1 // 子项目的索引,-1表示没有子项 );ii. nFormat:列的对齐方式,以LVCFMT_打头,即List View Control Format的缩写,有以下几种
LVCFMT_LEFT:左对齐
LVCFMT_RIGHT:右对齐
LVCFMT_CENTER:居中
!!最左侧的那一列必须使用LVCFMT_LEFT!!
!!其实可以不必按照0、1、2...的顺序来插入列,比如0、2、3也行,那么只要将1的那列的nWidth设为-1即可,这样其它参数都无效;
!!因此按照这个规则,不一定就是0的那列必须为LVCFMT_LEFT,如果0置为空列,那么后面的第一个非空列就是最左列,只要最左列必须为LVCFMT_LEFT即可;
4. 列表视图的操作:
1) 之前介绍的列表视图的创建,接下来的操作可以根据需要在任何地方(函数中)进行;
2) 插入项目:InsertItem
i. 原型:int CListCtrl::InsetItem(int nItem, LPCTSTR lpszItem, int nImage);
ii. nItem:表示该项目插入到第几号索引,原来位置的项目将会往后挪一位;
iii. lpszItem:插入项目的文本;
iv. nImage:该项目所对应的图标,这里是图形列表中图标的索引号;
v. 返回的是插入后项目的索引,如果失败则返回-1;
!!另一个版本:int CListCtrl::InsertItem(const LVITEM* pItem);
i. LVITEM是一个结构体,即List View Item的缩写,看一下定义:
typedef struct _LVITEM { UINT mask; // 项目标志 int iItem; // 项目索引 int iSubItem; // 子项目索引 UINT state; UINT stateMask; LPTSTR pszText; // 项目-子项目所确定的位置的文本 int cchTextMax; int iImage; // 项目图标在图形列表中的索引 LPARAM lParam; // 额外数据区的指针 int iIndent; } LVITEM;!!这里我们只注释了我们需要用到的数据域,其它数据域暂时用不到,不用理会;
3) 设置项目文本:SetItemText
i. 原型:BOOL CListCtrl::SetItemText(int nItem, int nSubItem, LPCTSTR lpszText);
ii. nItem-nSubItem:表示第几个项目的第几个子项目,nSubItem如果为0就表示该项目本身标签,只要在报表模式中nSubItem才可以大于0,表示该项目的子项目;
iii. lpszText是设置的文本,返回值表示调用是否成功;
4) 设置列表项目宽度的重要手段:GetStringWidth
i. 在通常情况下需要根据项目中文本的宽度来决定列表的宽度,如果列表过窄则部分文本显示不出来,过宽则空白太多也不美观;
ii. 可以通过文本来测量列表最最合适的宽度,原型:int CListCtrl::GetStringWidth(LPCTSTR lpsz) const;
iii. 该方法使CListCtrl独有的方法,它可以根据指定的字符串lpsz来计算出一个刚好合适的列表宽度并返回,注意!返回的是以像素为单位的;
5) 删除所有的项目:BOOL CListCtrl::DeleteAllItems(); // 返回值表示成功与否
5. 修改列表的样式:
1) 虽然在PreCreateWindow中已经设定好了默认的样式,但是有时候也有在程序中根据用户的响应来临时改变样式的需求,比如从菜单中选择列表的样式等;
2) 首先可以通过GetStyle来获取当前的样式:
i. 原型:DWORD CWnd::GetStyle() const;
ii. 该函数继承自CWnd,但是返回的是所有样式位,总共有32位,在被CListCtrl继承后,返回的不仅包含4大样式的信息,也包含其它各种杂七杂八的样式(比如左对齐、右对齐等等);
iii. 因此要获取真正的属于4大样式的哪一种必须借助于位掩码LVS_TYPEMASK,该标志和样式&后可以获得4大样式的标志位,因此判断当前是哪种4大样式的一种必须要这样写:列表只可能处在4大样式的其中一种状态,不可能同时处于两种样式的状态
DWORD dwStyle = GetStyle() & LVS_TYPEMASK; switch (dwStyle) { case LVS_ICON: ... case LVS_SMALLICON: ... ... }3) 临时修改列表样式:ModifyStyle
i. 原型:BOOL CWnd::ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0);
ii. 该函数继承自CWnd,该函数会触发窗口的重绘,即按照给定的新样式重绘;
iii. 该函数底层为了提高效率,采取消除和添加的方式指定新样式,dwRemove表示要删除的样式,而dwAdd表示要添加的样式;
iv. nFlags是要传给SetWindowPos的标志,如果传0表示不调用SetWindowPos,如果不为0则会回调SetWindowPos并将nFlags传给它,这里我们不需要用到这个功能,因此保持该参数的默认值即可;
v. 通常用该函数在4大样式之间进行转换,第一个参数必然填LVS_TYPEMASK,把4大样式先删去,第二个参数填指定的4大样式的一种,例如:ModifyStyle(LVS_TYPEMASK, LVS_SMALLICON); // 将样式转换为小图标模式
6. 列表的命中测试:
1)