转自:http://www.vckbase.com/index.php/wv/1352
首先,我们要创建一个基本对话框的MFC工程MFC_TreeCRTL(名字随便给一个)。然后在资源视图中插入两个Dialog,ID分别为IDD_DIALOG11和IDD_DIALOG211,都更改Style属性为Child,Border属性为None,为它们建立两个类,分别命名为Cdialog11和Cdialog211,并在MFC_TreeCRTLDlg.CPP文件中包含dialog11.h和dialog211.h两个头文件。再导入几个资源图标作为树形控件节点的图标及装饰面板。最后在主面板上添加一个CTreeCtrl控件,ID为默认,并在ClassWizard中添加它的一个变量,命名为m_mytree。
接着,我们进行具体代码编写。
我们必须在CMFC_TreeCRTLDlg类中加入这些变量和函数
CDialog * m_treePages[2];
CString node_name;
BOOL InitMytree();
我们还要在CMFC_TreeCRTLDlg类的构造函数中为m_treePages[2]分配空间,
m_treePages[0]=new Cdialog11;
m_treePages[1]=new Cdialog211;
InitMytree()函数为m_mytree的初始化过程。(原文遗漏,若没有这句,不显示)在OnInitDialog里面加上 InitMytree(); //关键
BOOL CMFC_TreeCRTLDlg::InitMytree()
{
//节点的图标
int i=0;
int i_count=2;
//载入图标
HICON icon[4];
icon[0]=AfxGetApp()->LoadIcon (IDI_ICON6);
icon[1]=AfxGetApp()->LoadIcon (IDI_ICON7);
//创建图像列表控件
CImageList* m_imagelist=new CImageList;
m_imagelist->Create(16,16,0,7,7);
m_imagelist->SetBkColor (RGB(255,255,255));
for(int n=0; n < i_count; n++)
m_imagelist->Add(icon[n]);//把图标载入图像列表控件
m_mytree.SetImageList(m_imagelist,TVSIL_NORMAL); //为m_mytree设置一个图像列表,使CtreeCtrl的节点显示不同的图标
m_mytree.SetBkColor(RGB(0,250,255));//设置m_mytree的背景色
//创建节点
//父节点
HTREEITEM root0=m_mytree.InsertItem(L"Dialog1",0,1,TVI_ROOT,TVI_LAST);
HTREEITEM root1=m_mytree.InsertItem(L"Dialog2",0,1,TVI_ROOT,TVI_LAST);
//一层子节点
HTREEITEM sub_son0=m_mytree.InsertItem(L"Dialog 1-1",0,1,root0,TVI_LAST);
HTREEITEM sub_son1=m_mytree.InsertItem(L"Dialog 2-1",0,1,root1,TVI_LAST);
//二层孙子节点
HTREEITEM sub_m_son0=m_mytree.InsertItem(L"Dialog 2-1-1",0,1,sub_son1,TVI_LAST);
//建立节点对应的Dialog
m_treePages[0]->Create(IDD_DIALOG11,this);
m_treePages[1]->Create(IDD_DIALOG211,this);
m_treePages[0]->ShowWindow(SW_SHOW);
m_treePages[1]->ShowWindow(SW_HIDE);
//把Dialog移到合适位置
CRect m_rect;
GetClientRect(m_rect);
m_rect.left=200;
m_treePages[0]->MoveWindow(m_rect);
m_treePages[1]->MoveWindow(m_rect);
return true;
}
始初化完成后,我们要添加CTreeCtrl的消息响应事件,这样才能让它按我们的要求起作用。我们打开Class Wizard点选IDC_TREE1添加TVN_SELCHANGED消息,并在消息响应函数中写入代码。
void CMFC_TreeCRTLDlg::OnTvnSelchangedTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
//LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
UpdateData(true);
CString node_name=m_mytree.GetItemText(pNMTreeView->itemNew.hItem);
//在标题栏显示节点信息
SetWindowText(node_name);
//切换面板
if(node_name=="Dialog 1-1"){
m_treePages[0]->ShowWindow(SW_SHOW);
m_treePages[1]->ShowWindow(SW_HIDE);
}
else if(node_name=="Dialog 2-1-1"){
m_treePages[0]->ShowWindow(SW_HIDE);
m_treePages[1]->ShowWindow(SW_SHOW);
}
UpdateData(false);
*pResult = 0;
}
以下转自: http://blog.sina.com.cn/s/blog_6a817a6c0100v2sx.html
树形控件TreeCtrl和下节要讲的列表控件
关于创建及风格:
树形控件可以用于树形的结构,其中有一个根接点(Root)然后下面有许多子结点,而每个子结点上有允许有一个或多个或没有子结点。MFC中使用CTreeCtrl类来封装树形控件的各种操作。通过调用Create创建一个窗口:
BOOL
dwStyle中可以使用以下一些树形控件的专用风格:
在5.80版中,即使没有图片,也会显示复选框。
这种风格一旦创建,将不能移除。只能destroy后再create一个新的。
TVS_DISABLEDRAGDROP
TVS_EDITLABELS
TVS_FULLROWSELECT
TVS_HASBUTTONS
TVS_HASLINES
TVS_INFOTIP
TVS_LINESATROOT
TVS_NOHSCROLL
TVS_NONEVENHEIGHT
TVS_NOSCROLL
TVS_NOTOOLTIPS
TVS_RTLREADING
TVS_SHOWSELALWAYS
TVS_SINGLEEXPAND
关于增加/删除
HTREEITEM
pszItem为显示的字符
hParent代表父结点的句柄,当前添加的结点会排在hInsertAfter表示的结点的后面,返回值为当前创建的结点的句柄。
下面的代码会建立一个如下形式的树形结构:
+---
+---
+---
HTREEITEM
//在根结点上添加Parent1
hItem
//在Parent1上添加一个子结点
hSubItem
//在Parent1上添加一个子结点,排在Child1_1后面
hSubItem
hSubItem
hItem
hItem
关于添加图标
如果你希望在每个结点前添加一个小图标,就必需先调用
CImageList*
指明当前所使用的ImageList,nImageListType为TVSIL_NORMAL。在调用完成后控件中使用图片以设置的ImageList中图片为准。然后调用InsertItem添加结点:
HTREEITEM
nImage为结点没被选中时所使用图片序号,nSelectedImage为结点被选中时所使用图片序号。下面的代码演示了ImageList的设置。
m_list.Create(IDB_TREE,16,4,RGB(0,0,0));
m_tree.SetImageList(&m_list,TVSIL_NORMAL);
m_tree.InsertItem( "Parent1 ",0,1);//添加,选中时显示图标1,未选中时显示图标0
关于插入标记
这是拖曳时经常用到的函数。
BOOL SetInsertMark( HTREEITEM hItem, BOOL fAfter = TRUE );
TRUE表示在hItem下面显示横杠,而FALSE则表示在上面。
同类函数还有:
SetInsertMarkColor,GetInsertMarkColor
关于得到/修改控件状态
此外CTreeCtrl还提供了一些函数用于得到/修改控件的状态。
HTREEITEM
BOOL
BOOL
BOOL
CString
BOOL
BOOL
BOOL
如何展开/收缩一个父节点?
-
CTreeCtrl::Expand
BOOL Expand( HTREEETEM hItem, UINT nColor );
返回值:如果成功则返回非零值;否则返回0。
参数:
说明:hItem 要被扩展的tree项的句柄。 nCode 用来指示要被进行的动作的标志。这个标志可以是下列值之一: · TVE_COLLAPSE 收缩列表。 · TVE_COLLAPSERESET 收缩列表并删除子项。 · TVE_EXPAND 展开列表。 · TVE_TOGGLE 如果列表当前是展开的则收缩列表;反之则展开列表。
此成员函数用来展开或收缩给定父项的子项列表(如果有)。
关于遍历:
此外如果想遍历树可以使用下面的函数:
HTREEITEM
HTREEITEM
HTREEITEM
HTREEITEM
<后面有两个遍历例程>
关于消息映射:
树形控件的消息映射使用ON_NOTIFY宏,形式如同:
ON_NOTIFY(
wNotifyCode为通知代码,id为产生该消息的窗口ID
memberFxn为处理函数,函数的原型如同void
TVN_SELCHANGED
TVN_ITEMEXPANDED
TVN_BEGINLABELEDIT
TVN_ENDLABELEDIT
TVN_GETDISPINFO
关于ON_NOTIFY有很多内容,将在以后的内容中进行详细讲解。
消息处理例程:
响应NM_RCLICK消息
void CLayerDialog::OnRclick(NMHDR* pNMHDR, LRESULT* pResult)
{
}
如何响应checkbox被单击?
响应NM_CLICK消息(checkbox就是分支前面的复选框,可从资源中修改属性添加)
void CLayerDialog::OnLclick(NMHDR *pNMHDR,LRESULT *pResult)
{
}
设置和获取checkbox的状态函数
GetCheck( )
SetCheck( )
如何知道某个点在CTreeCtrl上的位置
CTreeCtrl::HitTest
HTREEITEM HitTest( CPoint pt, UINT* pFlags );
返回值:
参数:
pt | in |
pFlags | out 其中flags测试结果可以是如下值: TVHT_BELOW 在客户区域下面 TVHT_NOWHERE 在客户区域中并在最后一项下面 TVHT_ONITEM 在与树项关联的位图或标签内 TVHT_ONITEMBUTTON 在与树项关联的按钮上 TVHT_ONITEMICON 在与树项关联的位图上 TVHT_ONITEMINDENT 在与树项关联的联线上 TVHT_ONITEMLABEL 在与树项关联的标签上 TVHT_ONITEMRIGHT 在树项的右侧区域中 TVHT_ONITEMSTATEICON 在用户定义的状态图标上 TVHT_TOLEFT 在客户区域的左侧 TVHT_TORIGHT 在客户区域的右侧 |
pHitTestInfo | in/out 一个包含点击测试的位置并接收测试结果的信息的TVHITTESTINFO结构的地址。 typedef struct _TVHITTESTINFO { |
说明:
此成员函数用来确定相对于一个tree view控件的客户区的指定点的定位。
当调用这个函数时,pt参数指定要测试的点的坐标。此函数返回位于指定点的项的句柄,或者如果没有项位于该点则返回NULL。另外,pFlags参数包含了指明指定点的定位的值。
关于动态提供结点所显示的字符
char
//添加结点
HTREEITEM
m_tree.SetItemData(hItem,
hItem
m_tree.SetItemData(hItem,
//处理消息
void
{
TV_DISPINFO*
pTVDI-> item.pszText=szOut[pTVDI-> item.lParam];//通过lParam得到需要显示的字符在数组中的位置
*pResult
}
关于编辑结点的显示字符
首先需要设置树形控件的TVS_EDITLABELS风格,在开始编辑时该控件将会发送TVN_BEGINLABELEDIT,你可以通过在处理函数中返回TRUE来取消接下来的编辑,在编辑完成后会发送TVN_ENDLABELEDIT,在处理该消息时需要将参数pNMHDR转换为LPNMTVDISPINFO,然后通过其中的item.pszText得到编辑后的字符,并重置显示字符。如果编辑在中途中取消该变量为NULL。下面的代码说明如何处理这些消息:
//处理消息
void
{
TV_DISPINFO*
if(pTVDI-> item.lParam==0);//判断是否取消该操作
*pResult
else
*pResult
}
//处理消息
void
{
TV_DISPINFO*
if(pTVDI-> item.pszText==NULL);//判断是否已经取消取消编辑
m_tree.SetItemText(pTVDI-> item.hItem,pTVDI-> pszText);//重置显示字符
*pResult
}
上面讲述的方法所进行的消息映射必须在父窗口中进行(同样WM_NOTIFY的所有消息都需要在父窗口中处理)。
关于修改树控件的背景位图
BOOL CMyTreeCtrl::SetBKImage(LPCTSTR LpszResource)
void CMyTreeCtrl::OnPaint()
void CMyTreeCtrl::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
void CMyTreeCtrl::OnItemexpanded(NMHDR* pNMHDR, LRESULT* pResult)
BOOL CMyTreeCtrl::OnEraseBkgnd(CDC* pDC)
我的实践代码:
MFC:
关于变量:
在资源文件的主对话框上添加一个CTreeCtrl控件,选中此控件点击右键->CalassWizard->Member Variables 在这项中双击CTreeCtrl控件的ID,关联这个控件与一个CTreeCtrl变量(eg m_TreeCtrl)
关于属性设置:
增加 TreeCtrl 的 TVS_HASBUTTONS,TVS_HASLINES、TVS_LINESATROOT Style,代码如下:
如何插入一个节点:
HTREEITEM hRoot,hItem,hItem1,hItem2,hSubItem,hSubItem1;
hRoot = m_TreeCtrl.InsertItem("我的电脑");//并不是不是真正意义上的根节点,只是在视觉效果上看起来是
hItem = m_TreeCtrl.InsertItem( "Parent1 ",hRoot);
hSubItem = m_TreeCtrl.InsertItem("child1",hItem);
hSubItem1 = m_TreeCtrl.InsertItem("child2",hItem,hSubItem);
hItem1 = m_TreeCtrl.InsertItem( "Parent2 ",hRoot,hItem);
hItem2 = m_TreeCtrl.InsertItem( "Parent3 ",hRoot,hItem1);
效果图:
首先,构造出来ImageList :
CImageList* imageList=new CImageList();
imageList->Create(19, 19, ILC_COLOR24|ILC_MASK, 20, 1);
//参数意义:参看:http://blog.sina.com.cn/s/blog_4b3c1f950100b0eh.html
HBITMAP hBitmap = (HBITMAP)LoadImage(NULL,"D:\Project\TEMP\1.bmp",IMAGE_BITMAP,
19,19,LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
CBitmap* m_bitmap = new CBitmap();
m_bitmap->Attach(hBitmap);
imageList->Add(m_bitmap,RGB(0, 0, 0));//参数意义,下面有解释
然后,把ImageList和TreeCtrl关联起来:
m_TreeCtrl.SetImageList(imageList,TVSIL_NORMAL);
注:这个关联必须在m_TreeCtrl插入节点之前。
然后,在插入子节点时这样:
hSubItem = m_TreeCtrl.InsertItem("child1",0,1,hItem);
//添加节点 "child1",未选中时图标为imageList的第0个,选中后图标为imageList的第1个.
效果图:
待解答.....
?????有什么方法能在子节点的位置上不是只是一个字符串,而是插入一个其他的控件呢????
待解答.....
GetWindowLong
SetWindowLong
int Add( CBitmap* pbmImage, COLORREF crMask );
int Add( HICON hIcon );
返回值:
如果成功,则为第一个新图象的基于零的索引,否则为-1。
参数:
pbmImage | 指向包含一个或多个图象的位图的指针。图象数由位图宽推断。 |
pbmMask | 指向包含掩码的位图的指针。如果无掩码与图象列表一起使用,则此参数被忽略。 |
crMask | 生成掩码的颜色。指定位图中的此颜色的每个像素被改为黑色,掩码中的相应位数被设置为1。 |
hIcon | 包含新图象的位图和掩码的图标的句柄。 |
说明:
调用此函数来添加一个或多个图象或图标到图象列表中。
遍历例程:
以下是采用递归完成的遍历树的函数:
遍历树
//hitem:待遍历树的根节点
void TreeVisit(HTREEITEM hItem)
{
if(ItemHasChildren(hItem))
{
HTREEITEM hChildItem = GetChildItem(hItem);
while(hChildItem!=NULL)
{
hChildItem = GetNextItem(hChildItem, TVGN_NEXT);
}
}
}
如何根据名称查找树中的某个节点(必须是节点名称是唯一的)
//item:待遍历树的根节点,strtext:待查找节点名称
HTREEITEM finditem(HTREEITEM item, CString strtext)
{
}