MFC VC 中 TreeView 解析
(一)树控制的主要功能
树控制和视(Tree Control&View)主要用来显示具有一定层次结构的数据项,如资源管理器中的磁盘目录等,以供用户在其中进行各种选择。树控制中的每个数据项包括数据项名称的文本字符串和用于表示该数据项的图像,每个数据项下面均可包含各种子项,整个结构就象目录树一样。对于包含各种子项的数据项,可通过鼠标双击来展开或合拢,这可以通过控制树的不同风格来实现树控制的不同显示形态。这些风格主要包括:
TVS_HASLINES 表示用连线来连接父项和它下面的各个子项,这可以使树的显示层次结构更加清晰,但在无父项的各子项之间并没有连线;
TVS_LINESATROOT 表示在无父项的各子项即根下面的各子项之间存在连线;
TVS_HASBUTTONS 表示在带有子项的父项前面增加一个带“+”或“-”的按钮,这使得用户也可以通过单击这个小按钮来实现子项的展开和合拢,当存在子项时,按钮的初始状态为“+”,当子项被展开时,按小按钮由“+”变为“-”号,当子项合拢时,小按钮由“-”变为“+”号,这一风格同样对于根项无效,如果需要可通过组合TVS_LINESATROOT风格来实现;
TVS_EDITLABELS表示允许让用户单击具有输入焦点的数据项来修改其名称。
对于树控制,MFC中也以两种形式来封装,即树控制(CTREECTRL)和树视(CTREEVIEW),来满足用户的不同需求,对于一般要求的用户如在对话框中应用,使用树控制比较方便,而对于具有较高要求的用户,在使用树视时还具有视窗口的各种方便特性,可以更好地满足文档/视结构的要求。当在窗口中使用树视时,树视会占满两个窗口的客户区域并自动随窗口的框架结构的调整而调整,并能够很好地处理诸如菜单、加速键和工具条中的各种命令消息。在使用树视时只要利用其成员函数CtreeView取得其一个引用,就可以象树控制一样方便地应用:CtreeCtrl &treeCtrl = GetTreeCtrl()。
(二)树控制的对象结构
1、树控制的建立方法
CtreeCtrl&treeCtrl 建立树控制对象结构
Create 建立树控制并绑定对象
树控制CTreeCtrl::Create的调用格式如下:
BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
其中参数dwStyle用来确定树控制的类型;rect用来确定树控制的大小和位置;pParentWnd用来确定树控制的父窗口,通用是一个对话框并且不能为NULL;nID用来确定树控制的标识。树控制的风格可以是下列值的组合:
TVS_HASLINES 表示树控制在各子项之间存在连线;
TVS_LINESATROOT 表示树控制在根项之间存在连线;
TVS_HASBUTTONS 表示树控制视在父项左侧存在展开合拢控制按钮;
TVS_EDITLABELS 表示可以控制鼠标单击修改树项的名称;
TVS_SHOWSELALWAYS 表示选中项即使在窗口失去输入焦点时仍然保持选中状态;
TVS_DISABLEDRAGDROP表示禁止树控制发送TVN_BEGINDRAG消息
2、树控制的属性类
树控制属性类包括取得树控制中项数GetCount
取得树控制中项相对于父项的偏移值GetIndent
取得树控制图像列表控制句柄GetImageList
设置树控制图像列表控制句柄SetImageList
取得匹配下一个树项GetNextItem
判断给定树项是否包含子项ItemHasChildren
取得树项子项GetChildItem
取得下一个同属树项GetNextSiblingItem
取得前一个同属树项GetPrevSiblingItem
取得父树项GetParentItem
取得第一个可视树项GetFirstVisibleItem
取得下一个可视树项GetNextVisible Item
取得前一个可视的树项GetPrevVisibleItem
取得被选中的树项GetSelectedItem
取得根树项GetRootItem
取得树项的属性GetItem
设置树项的属性SetItem
取得树项的状态GetItemState
设置树项的状态SetItemState
取得与树项关联图像GetItemImage
设置与树项关联图像SetItemImage
取得树项文本GetItemText
设置树项文本SetItemText
取得树项编辑控制句柄GetEditControl
3、树控制的操作方法
树控制的操作方法包括插入一个树项InsertItem
删除一个树项DeleteItem
删除所有树项DeleteAllItems
展开或合拢树项的子项Expand
选中特定树项SelectItem
选择一个树项作为第一个可视树项SelectSetFirstVisible
编辑一个可视的树项EditLabel
排序给定父树项的子树项SortChildren
(三)树控制的数据结构
在使用树控制时需要了解两个个非常重要的数据结构TV_ITEM和TV_INSERTSTRUCT,前一个数据结构是用来表示树控制的树项信息,后一个数据结构是用来定义将树项增加到数据控制中所需要的数据内容。另外,还需要NM_TREEVIEW、TV_DISPINFO和TV_HITTESTINFO三个数据结构,这几个数据结构的定义方法如下:
①基本数据项结构
typedef struct _TV_ITEM {
UINT mask; //结构成员有效性屏蔽位
HTREEITEM hItem; //数据项控制句柄
UINT state; //数据项状态
UINT stateMask; //状态有效性屏蔽位
LPSTR pszText; //数据项名称字符串
int cchTextMax; //数据项名称的最大长度
int iImage; //数据项图标索引号
int iSelectedImage;//选中数据项图标索引号
int cChildren; //子项标识
LPARAM lParam; //程序定义的32位数据
} TV_ITEM, FAR *LPTV_ITEM;
②插入树项结构
typedef struct _TV_INSER TSTRUCT {
HTREEITEM hParent; //父项控制句柄
HTREEITEM hInsertAfter; //插入树项的位置
TV_ITEM item; //数据项的结构
} TV_INSERTSTRUCT, FAR *LPTV_INSERTSTRUCT;
其中插入的位置如果是TVI_FIRST 或TVI_LAST ,则分别插入到树控制的最前面或最后面,如果是TVI_SORT ,则插入的树项自动插入到合适的位置。
③树控制通知消息结构
typedef struct _NM_TREEVIEW {
NMHDR hdr; //通知消息句柄
UINT action; //通知消息标志
TV_ITEM itemOld; //原来的数据结构
TV_ITEM itemNew; //新的数据结构
POINT ptDrag; //拖动指针
} NM_TREEVIEW;
④取得或设置数据结构
typedef struct _TV_DISPINFO { tvdi
NMHDR hdr; //通知消息控制句柄
TV_ITEM item; //数据项结构
} TV_DISPINFO;
⑤指针测试数据结构
typedef struct _TVHITTESTINFO { tvhtst
POINT pt; //客户区域屏幕坐标指针
UINT flags; //存放测试结果的变量
HTREEITEM hItem; //测试的数据项结构
} TV_HITTESTINFO, FAR *LPTV_HITTESTINFO;
其中flags测试结果可以是如下值:
TVHT_ABOVE 在客户区域上面
TVHT_BELOW 在客户区域下面
TVHT_NOWHERE 在客户区域中并在最后一项下面
TVHT_ONITEM 在与树项关联的位图或标签内
TVHT_ONITEMBUTTON 在与树项关联的按钮上
TVHT_ONITEMICON 在与树项关联的位图上
TVHT_ONITEMINDENT 在与树项关联的联线上
TVHT_ONITEMLABEL 在与树项关联的标签上
TVHT_ONITEMRIGHT 在树项的右侧区域中
TVHT_ONITEMSTATEICON 在用户定义的状态图标上
TVHT_TOLEFT 在客户区域的左侧
TVHT_TORIGHT 在客户区域的右侧
(四)树控制的应用技巧示例
1、设置树的风格
OnInitDialog函数中加入
//设置树的风格 DWORD dwStyle = GetWindowLong(m_webTree.m_hWnd,GWL_STYLE); //获取树控制原风格 dwStyle |= TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT; SetWindowLong(m_webTree.m_hWnd,GWL_STYLE,dwStyle);
2、删除树项功能的实现
在实现删除功能时,应对存在子项的树项进行提示,以警告用户是否连同其子项一起删除。
void CVCTREEDlg::OnDel() { //删除子项功能函数 HTREEITEM hSel=m_TreeCtrl.GetSelectedItem();//取得选项句柄; if(hSel==NULL) return;//无任何选项则返回 if(m_TreeCtrl.ItemHasChildren(hSel))//判断是否有子项 if(MessageBox("厂家下存在品名,一同删除?","警告",MB_YESNO)==IDNO) return; m_TreeCtrl.DeleteItem(hSel); }
3、排序功能的实现
void CVCTREEDlg::OnSort() { //排序子项功能函数 HTREEITEM hSel=m_TreeCtrl.GetSelectedItem();//取得选项句柄; if(hSel==NULL) return;//无任何选项则返回 m_TreeCtrl.SortChildren(hSel); }
4、查看功能的实现
查看功能用来查看选中树项的有关信息,函数中中显示了树项的文本名称和标识号,可以将这两个信息作为查找关键字,来查看其它更详细的信息。
void CVCTREEDlg::OnView() { //查看选中项功能函数 HTREEITEM hSel=m_TreeCtrl.GetSelectedItem();//取得选项句柄; if(hSel==NULL) return;//无任何选项则返回 CString cText=m_TreeCtrl.GetItemText(hSel);//取得数据项名 LONG IDs=m_TreeCtrl.GetItemData(hSel);//取得数据项序号 char temp[100]; wsprintf(temp,"厂家:%s 编号:%05d",cText,IDs); MessageBox(temp,"选择信息"); }
5、修改功能的实现
如果不进行其它处理,当修改树项的文本名称后,就会发现其未被修改,这是因为程序中没有对修改结果进行保存处理,这就要利用TV_DISPINFO结构和SetItemText函数对TVN_ENDLABELEDIT进行处理,这样就可以正确地实现修改功能。
void CVCTREEDlg::OnEndlabeleditTree(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; // TODO: Add your control notification handler code here if(pTVDispInfo->item.pszText==0) return;//用户取消修改操作 m_TreeCtrl.SetItemText(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);//设置新数据 *pResult = 0; }