树视(tree view)控件也称树控件,用于表示有层次关系的事物或能够进行分类划分的对象。树视控件中每个项目由项目名称和一个可选择的图标组成,其中的项目分为父项目昨子项目。一个父项目拥有一个子项目列表,双击该父项目可以展开或折叠其中的子项目。一个父项目拥有一个子项目列表,双击该父项目可以展开或折叠其中的子项目。父项目位于子项目的上一层,子项目又可以是低一层子项目的父项目,最上一个层的叫做根节点(root node),最低一层的项目叫叶节点(leaf node),介于它们之间的项目叫做枝节点(branch node)。
树视控件的应用也比较广泛,如Developer Studio的项目工作区窗口就使用了树视控件。树视控件有时与列表视控件一起使用,如Windows资源管理器左侧视图目录窗口使用一个树视图类CTreeView,而这种视图馀离一个与视图关联的树视控件。
有关树视控件的数据结构有几个,其中编程时经常要用到的数据结构是TV_ITEM结构和TV_INSERTSTRUCT结构。TVITEM结构(等同于TV_ITEM结构)用于定义项目,TVINSERTSTRUCT结构(等同于TV_INSERTSTRUCT结构)用于定义插入项,该结构含有一个TV_ITEM的结构成员,因此它实际上包含了要插入项目的属性。下面绘出TV_ITEM结构和TV_INSERTSTRUCT结构的定义。
typedef struct _TVITEM{
UINT mask; //掩码,说明TVITEM结构中哪些成员函数
HTREEITEM hItem; //项目句柄
UINT state; //项目的状态
UINT stateMask; //状态有效的屏蔽位
LPSTR pszText; //项目名称
int cchTextMax; //项目名称字符串的最大长度
int iImage; //当项目没有选中的关联图像列表的图像索引值
int iSelectedImage; //当项目选中时关联图像列表的图像索引值
int cChildren; //该项目是否包含子项目
LPARAM lParam; //程序定义的32位参数
}TVITEM,FAR* LPTVITEM;
typedef struct _TVINSERTSTRUCT{
HTREEITEM hParent; //要插入项的父项目的句柄
HTREEITEM hInsertAfter;//要插入上一项的句柄或位置标志值
TV_ITEM item; //要插入的项目
}TVINSERTSTRUCT,FAR* LPTVINSERTSTRUCT;
编程使用树视控件时经常需要重新设置控件的有关属性,树视控件常用的属性有:Has buttons表示父项目的前有一个“+”或"-"按钮可以展开或折叠项目;has lines表示用连线项目之间的层次关系;Lines at root表示在项目的最高层用连接项目与根节点连接;Edit labels表示可以编辑项目的名称;Check boxes表示项目的左侧有一个复选框;Single expand表示单击项目可以展开或折叠该项目。
封装树视控件的MFC类是CTreeCtrl类,CTreeCtrl类提供了对树视控件进行管理的成员函数,其中很多成员函数的功能与列表视控件类CListCtrl的成员函数相似,如项目的添加和删除,关联图像列表的设置等。CTreeCtrl类主要的成员函数有:InsertItem()或DeleteItem() 函数插入或删除一个项目;GetSelectedItem()函数返回当前选中的项目;GetChildItem()或GetParentItem()函数返回一个项目的子项目或父项目;GetRootItem()函数返回根项目;GetItemText()或SetItemText()函数获取或设置项目的文本串;Expand()函数展开或折叠项目;SetImageList()函数设置与树控件关联的图像列表。树视控件产生的消息也列表控件类似。
例: 编写一个对话框应用程序MyTree,对话框中有一具树视控件和其他一些如图1所示的按钮。树视控件用于显示一些有层次关系的项目,用户可通过“增加”或“删除”按钮向树视控件窗口添加或删除一个项目。
图1 对话框模板资源
[编程说明与实现]
(1)利用MFC AppWizard向导创建一个对话框应用程序MyTree,将对话框的标题改为“使用树视控件”。向对话框添加一个ID为IDC_TREECTL的树视控件,并设置控件的非默认属性Has buttons、Has lines和Lines at root。再向对话框添加“增加”(IDC_BUTNADD)和“删除”(IDC_BUTNDEL)两个命令按钮。利用ClassWizard类向志为树视控件添加一个类型为CTreeCtrl的成员变量m_TreeCtl。
(2)在对话框类初始脂成员函数OnInitDialog()中添加代码,模拟Developer Studio的项目工作区窗口,向树视控件加入一些项目。
BOOL CMyTreeDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
HTREEITEM hItemRoot,hItemClass,hItemRes,hItemFile; //声明项目句柄
hItemRoot=m_TreeCtl.InsertItem("Project",TVI_ROOT); //插入根项目Project
hItemClass=m_TreeCtl.InsertItem("Class",hItemRoot);//在根项目下面插入二级子项目
hItemRes=m_TreeCtl.InsertItem("Resource",hItemRoot);
hItemFile=m_TreeCtl.InsertItem("File",hItemRoot);
m_TreeCtl.InsertItem("CMyDialog",hItemClass); //在二级子项目下面插入三级子项目
m_TreeCtl.InsertItem("Dialog",hItemRes);
HTREEITEM hTreeSourF=m_TreeCtl.InsertItem("Source Files",hItemFile);
TVITEM tvItem; //InsertItem()成员函数有多种重载形式,声明要插入的项目
tvItem.mask=TVIF_TEXT;
tvItem.pszText="MyTreeDlg.cpp";
TV_INSERTSTRUCT tvInsert; //声明插入项
tvInsert.hParent=hTreeSourF;
tvInsert.hInsertAfter=TVI_LAST;
tvInsert.item=tvItem; //要插入的项目
m_TreeCtl.InsertItem(&tvInsert); //在子项目Source Files下面插入子项目
tvItem.mask=TVIF_TEXT;
tvItem.pszText="InputDlg.cpp";
tvInsert.hParent=hTreeSourF;
tvInsert.hInsertAfter=TVI_LAST;
tvInsert.item=tvItem; //要插入的项目
m_TreeCtl.InsertItem(&tvInsert); //在子项目Source Files下面插入子项目
return TRUE; // return TRUE unless you set the focus to a control
}
(3)单击“增加”按钮可以为树视控件窗口添加项目,而项目名称通过一个对话框进行输入,因此向项目添加一个ID为IDD_INPUT、标题为“请输入项目名称”的对话框,并向对话框添加一个ID为IDC_EDITITEM的编辑框和对应的静态文本控件。利用ClassWizard类向导创建对话框类CInputDlg,并为编辑框添加一个类型为CString的成员变量m_strItem。
(4)为“使用树视控件”对话框上的“增加”按钮添加BN_CLICKED消息处理函数,执行该函数时弹电子邮件"请输入项目名称"对话框,根据输入内容添加新的项目。
void CMyTreeDlg::OnButnadd()
{
// TODO: Add your control notification handler code here
CInputDlg dlg;
if(dlg.DoModal()==IDOK)
{
if(dlg.m_strItem=="")
{
MessageBox("项目名称为空!");
return;
}//当没有输入名称时返回
CString strItem=dlg.m_strItem;
MessageBox(strItem);
HTREEITEM hItem=m_TreeCtl.GetSelectedItem(); //获得树视控件的当前项目
m_TreeCtl.InsertItem(strItem,hItem); //在当前项目下面添加新项目
m_TreeCtl.Expand(hItem,TVE_EXPAND); //展开项目
}
}
(5)单击“删除”按钮可以删除树视控件窗口中当前项目,利用ClassWizard类向导为“删除”按钮添加BN_CLICKED消息处理函数。
void CMyTreeDlg::OnButndel()
{
// TODO: Add your control notification handler code here
HTREEITEM hItem=m_TreeCtl.GetSelectedItem(); //获得当前项目
if(hItem != NULL) m_TreeCtl.DeleteItem(hItem); //删除当前项目及它的下级项目
}
在MyTreeDlg.cpp文件的开始位置用#include指令包含InputDlg.h头文件。编译、链接并执行应用程序MyTree后,在树视控件窗口显示了已添加项目。可以向树视控件窗口添加或删除项目,其运行结果如图所示。