前面一节讲了树形控件tree control的简介、通知消息以及相关数据结构,本节继续讲下半部分,包括树形控件的创建、ctreectrl类的主要成员函数和应用实例。
树形控件的创建
mfc为树形控件提供了ctreectrl类,它封装了树形控件的所有操作。
树形控件的创建也是有两种方式,一种是在对话框模板中直接拖入tree control控件创建,另一种就是通过ctreectrl类的create成员函数创建。下面主要讲后者。
ctreectrl类的create成员函数的原型如下:
virtual bool create(
dword dwstyle,
const rect& rect,
cwnd* pparentwnd,
uint nid
);
此函数的原型与前面讲到的所有控件类的create函数都类似。dwstyle指定树形控件风格的组合,rect指定树形控件窗口的位置和大小,pparentwnd为指向树形控件父窗口的指针,nid指定树形控件的id。下面还是主要讲讲树形控件的主要风格以及含义。
tvs_disabledragdrop:禁止树形控件发送tvn_begindrag通知消息,即不支持拖动操作
tvs_editlabels:用户可以编辑节点的标签文本
tvs_hasbuttons:显示带有"+"或"-"的小方框来表示某项能否被展开或已展开
tvs_haslines:在父节点与子节点间连线以更清晰地显示树的结构
tvs_linesatroot:在根节点处连线
tvs_showselalways:即使控件失去输入焦点,仍显示出项的选择状态
同样,动态创建树形控件时,除了能够指定上述风格的组合外,一般还要指定ws_child和ws_visible风格。
在对话框模板中直接拖入tree control创建树形控件时,可以在树形控件的属性页中设置其风格,与上面的风格是对应的,例如,属性has lines对应的就是tvs_haslines风格。
ctreectrl类的主要成员函数
cimagelist* setimagelist(cimagelist * pimagelist,int nimagelisttype);
如果树节点需要显示图标时,则必须先创建一个cimagelist类的对象,并为其添加多个图像组成一个图像序列,然后调用setimagelist函数为树形控件设置图像序列,在用insertitem插入节点时传入所需图像在图像序列中的索引即可。后面的例子中会演示。参数pimagelist为指向图像序列类cimagelist的对象的指针,若为null则删除树形控件的所有图像。参数nimagelisttype指定图像序列的类型,可以是tvsil_normal(普通图像序列)或tvsil_state(状态图像序列,用图像表示节点的状态)。
uint getcount( ) const;
获取树形控件中节点的数量。
dword_ptr getitemdata(htreeitem hitem) const;
获取树形控件中某个指定节点的附加32位数据。参数hitem为指定的树节点的句柄。
bool setitemdata(htreeitem hitem,dword_ptr dwdata);
为树形控件中某个指定节点设置附加的32位数据。参数hitem同上,dwdata为要设置的32位数据。
cstring getitemtext(htreeitem hitem) const;
获取树形控件中某个指定节点的标签文本。参数hitem同上。返回值是包含标签文本的字符串。
bool setitemtext(htreeitem hitem,lpctstr lpszitem);
为树形控件中某个指定节点设置标签文本。参数hitem同上,lpszitem为包含标签文本的字符串的指针。
htreeitem getnextsiblingitem(htreeitem hitem) const;
获取树形控件中某个指定节点的下一个兄弟节点。参数hitem同上。返回值是下一个兄弟节点的句柄。
htreeitem getprevsiblingitem(htreeitem hitem) const;
获取树形控件中某个指定节点的上一个兄弟节点。参数hitem同上。返回值是上一个兄弟节点的句柄。
htreeitem getparentitem(htreeitem hitem) const;
获取树形控件中某个指定节点的父节点。参数hitem同上。返回值是父节点的句柄。
htreeitem getrootitem( ) const;
获取树形控件根节点的句柄。
htreeitem getselecteditem( ) const;
获取树形控件当前选中节点的句柄。
bool deleteallitems( );
删除树形控件中的所有节点。删除成功则返回true,否则返回false。
bool deleteitem(htreeitem hitem);
删除树形控件中的某个节点。参数hitem为要删除的节点的句柄。删除成功则返回true,否则返回false。
htreeitem insertitem(lpctstr lpszitem,int nimage,int nselectedimage,htreeitem hparent = tvi_root,htreeitem hinsertafter = tvi_last);
在树形控件中插入一个新节点。参数lpszitem为新节点的标签文本字符串的指针,参数nimage为新节点的图标在树形控件图像序列中的索引,参数nselectedimage为新节点被选中时的图标在图像序列中的索引,参数hparent为插入节点的父节点的句柄,参数hinsertafter为新节点的前一个节点的句柄,即新节点将被插入到hinsertafter节点之后。
bool selectitem(htreeitem hitem);
选中指定的树节点。参数hitem为要选择的节点的句柄。若成功则返回true,否则返回false。
树形控件的应用实例
最后还是给大家写一个简单的实例,说明clistctrl类的几个成员函数及树形控件通知消息等的使用方法。
此实例实现的功能:在一个树形控件中显示网站的简单结构分层,共有三层,分别为网站、各个分类和文章。用鼠标左键单击改变选中节点后,将选中节点的文本显示到编辑框中。另外,还要实现一个常见的效果,就是鼠标划过除根节点外的某个树节点时,显示相应的tip提示信息。下面是具体实现步骤:
1. 创建一个基于对话框的mfc工程,名称设置为“example31”。
2. 在自动生成的对话框模板idd_example31_dialog中,删除“todo: place dialog controls here.”静态文本框、“ok”按钮和“cancel”按钮。添加一个tree control控件,id设置为idc_web_tree,属性has buttons、has lines和lines at root都设为true,为了在鼠标划过某个节点时显示提示信息还需要将info tip属性设为true。再添加一个静态文本框和一个编辑框,静态文本框的caption属性设为“您选择的节点:”,编辑框的id设为idc_item_sel_edit,read only属性设为true。此时的对话框模板如下图:
3. 导入需要为树形控件的节点添加的图标。在这里找了三个32x32的icon图标,保存到工程的res目录下。然后在resource view资源视图中,右键点击icon节点,在右键菜单中选择“add resource...”,弹出“add resource”对话框,再从左边“resource type”列表中选择“icon”,点击右边的“import...”按钮,就可以选择三个图标文件进行导入了。导入成功后,分别修改它们id为idi_web_icon、idi_catalog_icon和idi_article_icon。
4. 为树形控件idc_web_tree添加ctreectrl类型的控件变量m_webtree。并在example31dlg.h文件中为cexample31dlg类添加成员对象:cimagelist m_imagelist;。
5. 在对话框初始化时,我们在树形控件中添加网站的树形结构,那么需要修改cexample31dlg::oninitdialog()函数为:
bool cexample31dlg::oninitdialog()
{
cdialogex::oninitdialog();
......略
// todo: add extra initialization here
hicon hicon[3]; // 图标句柄数组
htreeitem hroot; // 树的根节点的句柄
htreeitem hcataitem; // 可表示任一分类节点的句柄
htreeitem hartitem; // 可表示任一文章节点的句柄
// 加载三个图标,并将它们的句柄保存到数组
hicon[0] = theapp.loadicon(idi_web_icon);
hicon[1] = theapp.loadicon(idi_catalog_icon);
hicon[2] = theapp.loadicon(idi_article_icon);
// 创建图像序列cimagelist对象
m_imagelist.create(32, 32, ilc_color32, 3, 3);
// 将三个图标添加到图像序列
for (int i=0; i<3; i++)
{
m_imagelist.add(hicon[i]);
}
// 为树形控件设置图像序列
m_webtree.setimagelist(&m_imagelist, tvsil_normal);
// 插入根节点
hroot = m_webtree.insertitem(_t("鸡啄米"), 0, 0);
// 在根节点下插入子节点
hcataitem = m_webtree.insertitem(_t("it互联网"), 1, 1, hroot, tvi_last);
// 为“it互联网”节点添加附加的编号数据,在鼠标划过该节点时显示
m_webtree.setitemdata(hcataitem, 1);
// 在“it互联网”节点下插入子节点
hartitem = m_webtree.insertitem(_t("百度文章1"), 2, 2, hcataitem, tvi_last);
// 为“百度文章1”节点添加附加的编号数据,在鼠标划过该节点时显示
m_webtree.setitemdata(hartitem, 2);
// 在“it互联网”节点下插入另一子节点
hartitem = m_webtree.insertitem(_t("谷歌文章2"), 2, 2, hcataitem, tvi_last);
// 为“谷歌文章2”节点添加附加的编号数据,在鼠标划过该节点时显示
m_webtree.setitemdata(hartitem, 3);
// 在根节点下插入第二个子节点
hcataitem = m_webtree.insertitem(_t("数码生活"), 1, 1, hroot, tvi_last);
// 为“数码生活”节点添加附加的编号数据,在鼠标划过该节点时显示
m_webtree.setitemdata(hcataitem, 4);
// 在“数码生活”节点下插入子节点
hartitem = m_webtree.insertitem(_t("智能手机文章1"), 2, 2, hcataitem, tvi_last);
// 为“智能手机文章1”节点添加附加的编号数据,在鼠标划过该节点时显示
m_webtree.setitemdata(hartitem, 5);
// 在“数码生活”节点下插入另一子节点
hartitem = m_webtree.insertitem(_t("平板电脑文章2"), 2, 2, hcataitem, tvi_last);
// 为“平板电脑文章2”节点添加附加的编号数据,在鼠标划过该节点时显示
m_webtree.setitemdata(hartitem, 6);
// 在根节点下插入第三个子节点
hcataitem = m_webtree.insertitem(_t("软件开发"), 1, 1, hroot, tvi_last);
// 为“软件开发”节点添加附加的编号数据,在鼠标划过该节点时显示
m_webtree.setitemdata(hcataitem, 7);
// 在“软件开发”节点下插入子节点
hartitem = m_webtree.insertitem(_t("c++编程入门系列1"), 2, 2, hcataitem, tvi_last);
// 为“c++编程入门系列1”节点添加附加的编号数据,在鼠标划过该节点时显示
m_webtree.setitemdata(hartitem, 8);
// 在“软件开发”节点下插入另一子节点
hartitem = m_webtree.insertitem(_t("vs2010/mfc编程入门2"), 2, 2, hcataitem, tvi_last);
// 为“vs2010/mfc编程入门2”节点添加附加的编号数据,在鼠标划过该节点时显示
m_webtree.setitemdata(hartitem, 9);
// 在根节点下插入第四个子节点
hcataitem = m_webtree.insertitem(_t("娱乐休闲"), 1, 1, hroot, tvi_last);
// 为“娱乐休闲”节点添加附加的编号数据,在鼠标划过该节点时显示
m_webtree.setitemdata(hcataitem, 10);
// 在“娱乐休闲”节点下插入子节点
hartitem = m_webtree.insertitem(_t("玛雅文明文章1"), 2, 2, hcataitem, tvi_last);
// 为“玛雅文明文章1”节点添加附加的编号数据,在鼠标划过该节点时显示
m_webtree.setitemdata(hartitem, 11);
// 在“娱乐休闲”节点下插入另一子节点
hartitem = m_webtree.insertitem(_t("it笑话2"), 2, 2, hcataitem, tvi_last);
// 为“it笑话2”节点添加附加的编号数据,在鼠标划过该节点时显示
m_webtree.setitemdata(hartitem, 12);
return true; // return true unless you set the focus to a control
}
6. 我们希望在选中节点改变时,将最新的选择项实时显示到编辑框中,那么可以响应tvn_selchanged通知消息。为树形控件idc_web_tree的通知消息tvn_selchanged添加消息处理函数cexample31dlg::ontvnselchangedwebtree,并修改函数体如下:
void cexample31dlg::ontvnselchangedwebtree(nmhdr *pnmhdr, lresult *presult)
{
lpnmtreeview pnmtreeview = reinterpret_cast<lpnmtreeview>(pnmhdr);
// todo: add your control notification handler code here
*presult = 0;
cstring strtext; // 树节点的标签文本字符串
// 获取当前选中节点的句柄
htreeitem hitem = m_webtree.getselecteditem();
// 获取选中节点的标签文本字符串
strtext = m_webtree.getitemtext(hitem);
// 将字符串显示到编辑框中
setdlgitemtext(idc_item_sel_edit, strtext);
}
7. 还有一个功能需要实现,那就是鼠标划过除根节点外的某个树节点时,显示相应的tip提示信息,本实例中提示信息为节点的编号。这需要响应tvn_getinfotip通知消息。为树形控件idc_web_tree的通知消息tvn_getinfotip添加消息处理函数cexample31dlg::ontvngetinfotipwebtree,并修改函数体如下:
void cexample31dlg::ontvngetinfotipwebtree(nmhdr *pnmhdr, lresult *presult)
{
lpnmtvgetinfotip pgetinfotip = reinterpret_cast<lpnmtvgetinfotip>(pnmhdr);
// todo: add your control notification handler code here
*presult = 0;
nmtvgetinfotip* ptvtipinfo = (nmtvgetinfotip*)pnmhdr; // 将传入的pnmhdr转换为nmtvgetinfotip指针类型
htreeitem hroot = m_webtree.getrootitem(); // 获取树的根节点
cstring strtext; // 每个树节点的提示信息
if (ptvtipinfo->hitem == hroot)
{
// 如果鼠标划过的节点是根节点,则提示信息为空
strtext = _t("");
}
else
{
// 如果鼠标划过的节点不是根节点,则将该节点的附加32位数据格式化为字符串
strtext.format(_t("%d"), ptvtipinfo->lparam);
}
// 将strtext字符串拷贝到ptvtipinfo结构体变量的psztext成员中,这样就能显示内容为strtext的提示信息
wcscpy(ptvtipinfo->psztext, strtext);
}
8. 运行程序,弹出结果对话框。效果如下图:
树形控件的知识就讲到这里了,相比之前的控件可能稍有复杂。不过用的多了,就会觉得得心应手了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
更多vs2010/mfc编程(常用控件:树形控件tree control控件创建h和实例)。