MFC树控件的简单入门
本文简单介绍了有关MFC中树形控件的最基本的用法,鉴于水平有限,仅希望能够读者通过简单的编程实例,起到对树形控件入门之目的。因为笔者对MFC知识点的学习也都是从实例中学习,这样效率会相对较高,好了不说废话了,开始…
1. 新建一名为“MyTree”的对话框(Dialog based)应用程序项目(MFC AppWizard(EXE)),编译完成后效果如下:
图1
2. 删除对话框中的静态文本控件,并添加Tree Contrl控件和三个 Button控件,各控件属性见下表,完成效果如下:
表1
序号 | 属性 | 内容 | 备注 |
1 | 树形控件 | IDC_TREE |
|
2 | 按钮控件 | IDC_BTN_INITIAL | 初始化操作 |
3 | 按钮控件 | IDC_BTN_DELETE | 删除一个节点 |
4 | 按钮控件 | IDC_BEN_CLEAR | 删除全部节点 |
图2
3. 在对话框中的树型控件上右键添加CTreeCtrl类的变量m_treeCtrl,此时在类视图中的CMyTreeDlg类中增加了私有变量m_treeCtrl。
4. 在初始化按钮上双击,在其初始化处理函数内添加一些代码,完成初始化工作,初始化工作主要实现树型控件内各个节点的添加工作,此时先在MSDN中找到CTreeCtrl类的(member)成员,依次参考Create/等成员函数,可参考下面代码:
void CMyTreeDlg::OnBnClickedBtnInitial()
{
//添加根节点
HTREEITEM root = m_treeCtrl.InsertItem(_T("root"));
//添加两个父节点
HTREEITEM parent1 = m_treeCtrl.InsertItem(_T("parent1"));
HTREEITEM parent2 = m_treeCtrl.InsertItem(_T("parent2"));
//为父节点添加子节点,child2在child1之后
HTREEITEM child1 = m_treeCtrl.InsertItem(_T("child1"),parent1);
HTREEITEM child2 = m_treeCtrl.InsertItem(_T("child2"),parent1,child1);
HTREEITEM child3 = m_treeCtrl.InsertItem(_T("child3"),parent1,child2);
HTREEITEM child11 = m_treeCtrl.InsertItem(_T("child11"),parent2);
HTREEITEM child22 = m_treeCtrl.InsertItem(_T("child22"),parent2,child11);
HTREEITEM child33 = m_treeCtrl.InsertItem(_T("child33"),parent2,child22);
}
5. 此时运行程序,多次点击初始化出现以下界面:
图3
此时我们发现两处不足(bug): 一是每次点击初始化按钮就出现一个树结构,实际上我们需要的是一组树结构,不应该重复相同的树结构;二是图中显示的树结构,父节点与子节点之间没有连线,看起来不直观,需要修改树控件的类型(style)。
解决第一个 bug的方法是:在CMyTreeDlg中定义一个BOOL型变量m_result, 该变量初始化为FALSE, 对上述代码进行如下修改:实现点击一次初始化按钮,显示树结构;再次点击将把所有节点删除的效用!
解决第二个bug的方法是:由于树型控件类继承了窗口类CWnd,所以可以利用CWnd类中的ModifyStyle()函数,可以修改树控件的style,使其拥有连线功能,同时我们还增添了button以及连线颜色、背景颜色的设置,算是买一送一吧!具体修改后的代码及界面显示如下(真是人配衣裳马配鞍,狗配铃铛跑得欢啊!):
void CMyTreeDlg::OnBnClickedBtnInitial()
{
//因为在对话框中已经定义了树形控件变量,该控件在对话框生成时,就已经调用树形类的create函数,完成了初始化工作;因此如果想修改树形控件的stytle需要调用Modify
if (FALSE == m_result)
{
//修改树控件style
m_treeCtrl.ModifyStyle(0,TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS);
//增加了控件颜色修改
m_treeCtrl.SetLineColor(RGB(120,100,0));
m_treeCtrl.SetBkColor(RGB(73,169,51));
m_treeCtrl.SetTextColor(RGB(255,0,0));
//添加根节点
HTREEITEM root = m_treeCtrl.InsertItem(_T("root"));
//添加两个父节点
HTREEITEM parent1 = m_treeCtrl.InsertItem(_T("parent1"));
HTREEITEM parent2 = m_treeCtrl.InsertItem(_T("parent2"));
//为父节点添加子节点
HTREEITEM child1 = m_treeCtrl.InsertItem(_T("child1"),parent1);
HTREEITEM child2 = m_treeCtrl.InsertItem(_T("child2"),parent1,child1);
HTREEITEM child3 = m_treeCtrl.InsertItem(_T("child3"),parent1,child2);
HTREEITEM child11 = m_treeCtrl.InsertItem(_T("child11"),parent2);
HTREEITEM child22 = m_treeCtrl.InsertItem(_T("child22"),parent2,child11);
HTREEITEM child33 = m_treeCtrl.InsertItem(_T("child33"),parent2,child22);
m_result = TRUE;
}
else
{
m_treeCtrl.DeleteAllItems();
m_result =FALSE;
}
}
图4
6. 在对话框资源中双击删除一个节点按钮,添加删除一个节点的功能函数。此时我们有两步要做,删除一个节点,我们用到CTreeCtrl类中的DeleteItem()成员函数,第二步,我们要确定那个节点被选中,此时用到GetSeletedItem()成员函数,参考两个函数的MSDN中的例子,我们可以轻松实现删除一个节点功能,代码如下:
void CMyTreeDlg::OnBnClickedBtnDelete()
{
//选择节点
HTREEITEM hItem = m_treeCtrl.GetSelectedItem();
if ((hItem != NULL))
{
m_treeCtrl.DeleteItem(hItem);
}
}
7. 依照前面两部分内容,有关删除全部节点的功能, 还有难度吗?其实我们前面在初始化时已经提前引入了有关删除全部节点的函数!她是…? O(∩_∩)O~,想必此时的你对树形控件的使用已经有感觉了吧!
图5
水滴穿石,贵在持之以恒
VC 中的Tree Control
2010-08-06 11:08:15| 分类: 工作 阅读372 评论1 字号:大中小 订阅
转载地址:http://hi.baidu.com/lightningyaoyao/blog/item/34744d4f4e632a34afc3abc3.html
Tree Control 的属性和方法比较多少,用起来确实麻烦,但其强大的功能和令人耳目一新的视觉效果值得我们去学习,我从网上收到一篇文章,较详细的的讲解了它的使用,稍作整理,在此和大家共享:
通过“FILE->NEW->PROJECTS->MFC AppWizard(EXE)”建立名为VCTREE的工程,在建立过程中选择基于对话框(Dialog based)的应用;将对话框中的默认控件删除,并将所有对话框属性中的Language域设置为Chinese(P.R.C.),以使应用程序支持中文;建立两个图标IDI_PM和IDI_CJ,用来表示图标的选中和非选中状态,对于每个图标都应建立32X32和16X16两种大小,以保证程序的需要;在对话框窗口中添加树控制对象(TREE CONTROL),并设置五个按钮“增加|删除|查看|排序|关闭”,其对应标识分别如下:
控制名称 标题名称 标识符号
树控制 IDC_TREECTRL
按钮 增 加 IDC_ADD
删 除 IDC_DEL
查 看 IDC_VIEW
排 序 IDC_SORT
关 闭 IDOK
选中树控制控件,选择“VIEW->ClassWizard->Memory Variables。 IDC_TREECTRL 引入成员变量,其变量类型为:
变量名 种类 变量类型
m_TreeCtrl Control CTreeCtrl
同时利用“MESSAGES MAP”为各命令按钮增加控制功能函数。
然后在代码文件VCTREEDlg.CPP中分别加入如下控制代码:
(1)在文件开始处增加图像列表定义
CImageList Cil1,Cil2;//大小图标像列表
(2)在初始化文件开始处增加代码
BOOL CVCTREEDlg::OnInitDialog()
{ CDialog::OnInitDialog();
......//原来其它代码
// TODO: Add extra initialization here
// 此处开始增加代码
Cil1.Create(16,16,ILC_COLOR,2,2);
Cil1.Add(AfxGetApp()->LoadIcon(IDI_PM));
Cil1.Add(AfxGetApp()->LoadIcon(IDI_CJ));
m_TreeCtrl.SetImageList(&Cil1,TVSIL_NORMAL); file://设置图象列表
DWORD dwStyles=GetWindowLong(m_TreeCtrl.m_hWnd,GWL_STYLE);//获取树控制原风格
dwStyles|=TVS_EDITLABELS|TVS_HASBUTTONS|TVS_HASLINES|TVS_LINESATROOT;
SetWindowLong(m_TreeCtrl.m_hWnd,GWL_STYLE,dwStyles);//设置风格
wchar_t * CJ[4]={L"玉溪卷烟厂",L"云南卷烟厂",L"沈阳卷烟厂",L"成都卷烟厂"};//根数据名称
wchar_t * PM[4][5]={
{L"红梅一",L"红梅二",L"红梅三",L"红梅四",L"红梅五"},//产品数据项
{L"白梅一",L"白梅二",L"白梅三",L"白梅四",L"白梅五"},
{L"绿梅一",L"绿梅二",L"绿梅三",L"绿梅四",L"绿梅五"},
{L"青梅一",L"青梅二",L"青梅三",L"青梅四",L"青梅五"}};
int i,j;
HTREEITEM hRoot,hCur;//树控制项目句柄
TV_INSERTSTRUCT TCItem;//插入数据项数据结构
TCItem.hParent=TVI_ROOT;//增加根项
TCItem.hInsertAfter=TVI_LAST;//在最后项之后
TCItem.item.mask=TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE;//设屏蔽
TCItem.item.pszText="数据选择";
TCItem.item.lParam=0;//序号
TCItem.item.iImage=0;//正常图标
TCItem.item.iSelectedImage=1;//选中时图标
hRoot=m_TreeCtrl.InsertItem(&TCItem);//返回根项句柄
for(i=0;i<4;i++){//增加各厂家
TCItem.hParent=hRoot;
TCItem.item.pszText=CJ[i];
TCItem.item.lParam=(i+1)*10;//子项序号
hCur=m_TreeCtrl.InsertItem(&TCItem);
for(j=0;j<5;j++){//增加各产品
TCItem.hParent=hCur;
TCItem.item.pszText=PM[i][j];
TCItem.item.lParam=(i+1)*10+(j+1);//子项序号
m_TreeCtrl.InsertItem(&TCItem);
}
m_TreeCtrl.Expand(hCur,TVE_EXPAND);//展开树
}
m_TreeCtrl.Expand(hRoot,TVE_EXPAND);//展开上一级树
return TRUE; // return TRUE unless you set the focus to a control
}
(3)增加树项功能的实现
在增加树项功能时,除了需要定义和设置插入树项的数据结构之外,还需要注意的是新增树项的名称初始时均为“新增数据”,增加后允许用户给数据项设置自定义名称。在编程时应特别注意m_TreeCtrl.EditLabel(hInsert);后面不能跟任何其它程序命令,否则这条编辑指令无效。
void CVCTREEDlg::OnAdd()
{ file://增加子项功能函数
HTREEITEM hSel=m_TreeCtrl.GetSelectedItem();//取得选择项句柄
if(hSel==NULL) return;//无任何选项则返回
static int nAddNo=100;//编号大于100为新增数据
TV_INSERTSTRUCT TCItem;//定义插入项数据结构
TCItem.hParent=hSel; file://设置父项句柄
TCItem.hInsertAfter=TVI_LAST;//在最后增加
TCItem.item.mask=TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE;//设屏蔽
TCItem.item.pszText="新增数据";
TCItem.item.lParam=nAddNo++;//索引号增加
TCItem.item.iImage=0;//正常图标
TCItem.item.iSelectedImage=1;//选中时图标
HTREEITEM hInsert=m_TreeCtrl.InsertItem(&TCItem);//增加
m_TreeCtrl.Expand(hSel,TVE_EXPAND);
m_TreeCtrl.EditLabel(hInsert);//修改增加的数据
}
(4)删除树项功能的实现
在实现删除功能时,应对存在子项的树项进行提示,以警告用户是否连同其子项一起删除。
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);
}
(5)排序功能的实现
排序功能是对所选中的树项的所有子项按字符中顺序进行排序,如果想要按照其它规则进行排序,应利用SortChildrenItemBC()函数进行自行开发排序程序,这个自行开发的函数与列表控制中实现的函数基本相同,可兴趣的读可以试验。
void CVCTREEDlg::OnSort()
{ //排序子项功能函数
HTREEITEM hSel=m_TreeCtrl.GetSelectedItem();//取得选项句柄;
if(hSel==NULL) return;//无任何选项则返回
m_TreeCtrl.SortChildren(hSel);
}
(6)查看功能的实现
查看功能用来查看选中树项的有关信息,函数中中显示了树项的文本名称和标识号,可以将这两个信息作为查找关键字,来查看其它更详细的信息。
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,"选择信息");
}
(7)修改功能的实现
如果不进行其它处理,当修改树项的文本名称后,就会发现其未被修改,这是因为程序中没有对修改结果进行保存处理,这就要利用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;
}