树视控件是一种特殊的列表,它能以树形分层结构显示数据。在树视图中,每个表项显示一个标题(Label),有时还会显示一幅图象,图象和标题分别提供了对数据的形象和抽象描述。树视图非常适合显示象目录,网络结构等这样的复杂数据.传统的列表框不能分层显示数据,因此树形视图可以看作是对列表框的一种重要改进
树视图是一种复杂的控件,它的复杂性体现在数据项之间具有分支和层次关系.例如,如果要向树形视图中加入新的项,则必需描述出该项与树形视图中已有项的相互关系,而不可能象往列表框中加入新项那样,调用一下AddString就完事了.另外,树形视图可以在每一项标题的左边显示一幅图象,这使控件显得更加形象生动,但同时也增加了控件的复杂程度.
8.1树视常用的数据结构
TV_ITEM结构.该结构用来描述一个表项,它包含了表项的各种属性,其定义如下
typedef struct _TV_ITEM
{ tvi
UINT mask; /*包含一些屏蔽位(下面的括号中列出)的组合,用来表明结构的哪些成员是有效的*/
HTREEITEM hItem; //表项的句柄(TVIF_HANDLE)
UINT state; //表项的状态(TVIF_STATE)
UINT stateMask; //状态的屏蔽组合(TVIF_STATE)
LPSTR pszText; //表项的标题正文(TVIF_TEXT)
int cchTextMax; //正文缓冲区的大小(TVIF_TEXT)
int iImage; //表项的图象索引(TVIF_IMAGE)
int iSelectedImage; //选中的项的图象索引(TVIF_SELECTEDIMAGE)
int cChildren; /*表明项是否有子项(TVIF_CHILDREN),为1则有,为0则没有*/
LPARAM lParam; //一个32位的附加数据(TVIF_PARAM)
} TV_ITEM, FAR *LPTV_ITEM;
如果要使树形视图的表项显示图象,需要为树形视图建立一个位图序列,这时,iImage说明表项显示的图象在位图序列中的索引,iSelectedImage则说明了选中的表项应显示的图象,在绘制图标时,树形视图可以根据这两个参数提供的索引在位图序列中找到对应的位图.lParam可用来放置与表项相关的数据,这常常是很有用的.state和stateMask的常用值在表6.25中列出,其中stateMask用来说明要获取或设置哪些状态.
TV_INSERTSTRUCT结构.在向树形视图中插入新项时要用到该结构,其定义为
typedef struct _TV_INSERTSTRUCT {
HTREEITEM hParent; //父项的句柄
HTREEITEM hInsertAfter; //说明应插入到同层中哪一项的后面
TV_ITEM item;
} TV_INSERTSTRUCT;
如果hParent的值为TVI_ROOT或NULL,那么新项将被插入到树形视图的最高层(根位置).hInsertAfter的值可以是TVI_FIRST、TVI_LAST或TVI_SORT,其含义分别是将新项插入到同一层中的开头、最后或排序插入.
NM_TREEVIEW结构.树形视图的大部分通知消息都会附带指向该结构的指针以提供一些必要的信息.该结构的定义为
typedef struct _NM_TREEVIEW { nmtv
NMHDR hdr; //标准的NMHDR结构
UINT action; //表明是用户的什么行为触发了该通知消息
TV_ITEM itemOld; //旧项的信息
TV_ITEM itemNew; //新项的信息
POINT ptDrag; //事件发生时鼠标的客户区坐标
} NM_TREEVIEW;
TV_KEYDOWN结构.提供与键盘事件有关的信息.该结构的定义为
pedef struct _TV_KEYDOWN { tvkd
NMHDR hdr; //标准的NMHDR结构
WORD wVKey; //虚拟键盘码
UINT flags; //为0
} TV_KEYDOWN;
TV_DISPINFO结构.提供与表项的显示有关的信息.该结构的定义为
typedef struct _TV_DISPINFO { tvdi
NMHDR hdr;
TV_ITEM item;
} TV_DISPINFO;
MFC的CTreeCtrl类封装了树形视图.
8.2 CTreeCtrl类的成员函数
CTreeCtrl类提供了大量的成员函数.对于常用的函数,这里结合实际应用的需要,介绍如下:
向树形视图中插入新的表项.首先应提供一个TV_INSERTSTRUCT结构并在该结构中对插入项进行描述.如果要在树形视图中显示图象,则应该先创建一个CImageList对象并使该对象包含一个位图序列,然后调用SetImageList为树形视图设置位图序列.然后调用InsertItem函数把新项插入到树形视图中.函数的声明为
CImageList* SetImageList( CImageList * pImageList, int nImageListType );
参数pImageList指向一个CImageList对象,参数nImageListType一般应为TVSIL_NORMAL.
HTREEITEM InsertItem( LPTV_INSERTSTRUCT lpInsertStruct );
参数lpInsertStruct指向一个TV_INSERTSTRUCT结构.函数返回新插入项的句柄.
用DeleteItem来删除指定项,用DeleteAllItems删除所有项.函数的声明为
BOOL DeleteItem( HTREEITEM hItem );
BOOL DeleteAllItems( );
操作成功则函数返回TRUE,否则返回FALSE.
树形视图控件会根据用户的输入自动展开或折叠子项.但有时需要在程序中展开或折叠指定项,则应该调用Expand,该函数的声明为
BOOL Expand( HTREEITEM hItem, UINT nCode );
参数hItem指定了要展开或折叠的项.参数nCode是一个标志,指定了函数应执行的操作,它可以是TVE_COLLAPSE(折叠)、TVE_COLLAPSERESET(折叠并移走所有的子项)、TVE_EXPAND(展开)或TVE_TOGGLE(在展开和折叠状态之间翻转).
要查询或设置选择项,应调用GetSelectedItem或SelectItem.函数的声明为
HTREEITEM GetSelectedItem( );
BOOL SelectItem( HTREEITEM hItem );
要对指定的项查询或设置,可调用GetItem和SetItem.用这两个功能强大的函数,几乎可以查询和设置项的所有属性,包括表项的正文、图像及选择状态.函数的声明为
BOOL GetItem( TV_ITEM* pItem );
BOOL SetItem( TV_ITEM* pItem );
参数pItem是指向TV_ITEM结构的指针,函数是通过该结构来查询或设置指定项的,在调用函数前应该使该结构的hItem成员有效以指定表项.CTreeCtrl还提供了一系列函数可完成GetItem和SetItem的部分功能,其中GetItemState、GetItemText、GetItemData、GetItemImage和ItemHasChildren函数用于查询,SetItemState、SetItemText、SetItemData和SetItemImage函数用于设置.
在使用树形视图控件时,一个经常遇到的问题是对于一个已知表项,如何找到与该项有某种关系的项,例如,父项、子项、兄弟项、下一个或前一个可见的项.利用功能强大的GetNextItem函数,可以解决这个问题.该函数也可以用来搜索具有某种状态的表项.GetNextItem在遍历树形视图时是很有用的,它的声明为
HTREEITEM GetNextItem( HTREEITEM hItem, UINT nCode );
参数hItem指定了一个项.参数nCode是一个标志,标明了与指定项的关系,nCode可以是如表8.1所示的各种标志.如果找到相关的项,函数返回该项的句柄,否则函数返回NULL.