树状控件的相关编程(转自努力工作的祥子)

来源:互联网 发布:淘宝网店开 编辑:程序博客网 时间:2024/06/15 21:27

在权限管理的项目中,我遇到了需要Tree Control控件的相关编程,在网上找了一篇,对我挺有帮助的,所以收藏过来,顺便改进一下。 

下面是文章的全部内容:

VC6中树状控件相较其它的控件如编辑框、按钮、IP地址来说编程实现复杂一点,但是相应的可以实现的功能也多一些,最近我在学习利用VC6进行SNMP编程过程中就需要用到树状控件,另外还需要利用CString类来对字符串进行一些处理,由此就萌生了一个想法,即利用树状控件作一个程序,该程序左边是一个树状控件,里面列出了对字符串的各种操作(如获取字符串的长度,去掉左边/右边的空字符等),右边是对应的各种操作的对话框,选取某个操作的时候,会切换到对应的对话框中。这是一个初步的想法,为了实现这个想法,我必须先在以下几个方面进行突破:1、对树状控件进行编程,在树状控件上绘制图标,添加文字描述,实现父节点、子节点、孙子节点的三层描述,2、编程实现字符串的各种操作,这些先在一个独立的程序中完成的,通过预先解决CString类的操作,减少后期程序融合时不必要的麻烦,3、在一个界面中实现树状控件中各叶子节点之间切换时,对应的各对话框之间切换。参考资料我选择是《Visual C++6.0技术内幕》和微软在线的MSDN,下面就是我具体的实现步骤。
《Visual C++6.0技术内幕》这本书的ex06b的例子中有一段是关于树控件编程的,我们可以拿来借鉴一下,具体的操作如下:
一、新建一个基于单文档的MFC应用程序,名字定为mytreedia,添加一个新的对话框,在其中添加一个树状控件,将其属性中的“Styles”设为如图1所示(即选中了Has buttons、Has lines、Line at root三项)。

图1
为这个对话框建立一个新的类,类名定为Cmytreediao。下面我们要做的就是能够调置一个触发开关(即点鼠标左键),能够把这个新的对话框调出来。
首先在mytreediaView.cpp这个文件中查找ondraw,找到后修改这个函数,如下:
void CMytreediaView::OnDraw(CDC* pDC)
{
 //CMytreediaDoc* pDoc = GetDocument();
 //ASSERT_VALID(pDoc);
 // TODO: add draw code for native data here
 pDC->TextOut(100,100,"点击鼠标左键即可弹出一个新的对话框!");
}
这时我们可以先运行一下,看看效果(经常的在完成一个编程阶段时就运行是个好习惯,这样可以让我们及时发现问题,不用等所有编程结束后为出现的一大堆错误提示而头痛),如图2所示

图2
当然这时我们如果点击鼠标左键是不会真的弹出一个对话框来,下面我们就要编程实现它。
我们肯定要编辑CMytreediaView类中的WM_LBUTTONDOWN消息,先把#include "mytreediao.h"这个头文件包含进来,然后编辑如下代码:
void CMytreediaView::OnLButtonDown(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
 Cmytreediao dlg;
 dlg.DoModal();
 CView::OnLButtonDown(nFlags, point);
}
程序运行的结果如图3所示:

图3
其实主要是DoModal()这条语句起作用,这也是基于单文档的MFC程序中弹出一个新的对话框的方法。
接下来我们要对树状控件进行编程,先导入一些图标文件,然后在mytreediao.h这个头文件中定义一个私有的变量
private:
 CImageList m_imageList;
然后在Cmytreediao中编辑WM_INITDIALOG消息,在其中添加如下代码:
BOOL Cmytreediao::OnInitDialog()
{
 CDialog::OnInitDialog();
 
 // TODO: Add extra initialization here
 HICON hIcon[8];
 int n;
 m_imageList.Create(16, 16, 0, 8, 8); // 32, 32 for large icons
 hIcon[0] = AfxGetApp()->LoadIcon(IDI_WHITE);
 hIcon[1] = AfxGetApp()->LoadIcon(IDI_BLACK);
 hIcon[2] = AfxGetApp()->LoadIcon(IDI_RED);
 hIcon[3] = AfxGetApp()->LoadIcon(IDI_BLUE);
 hIcon[4] = AfxGetApp()->LoadIcon(IDI_YELLOW);
 hIcon[5] = AfxGetApp()->LoadIcon(IDI_CYAN);
 hIcon[6] = AfxGetApp()->LoadIcon(IDI_PURPLE);
 hIcon[7] = AfxGetApp()->LoadIcon(IDI_GREEN);
 for (n = 0; n < 8; n++) {
    m_imageList.Add(hIcon[n]);
}
再运行一下,程序没有错误,但是也没有看到相应的图标,想想也是,我们没有为图标放在哪个地方进行编程,而且图标也要和文字标识放在一起才有意义,我们继续努力。
继续在BOOL Cmytreediao::OnInitDialog()中添加代码
 CTreeCtrl* pTree = (CTreeCtrl*) GetDlgItem(IDC_TREE1);
 pTree->SetImageList(&m_imageList, TVSIL_NORMAL);
 // tree structure common values
 TV_INSERTSTRUCT tvinsert;
 tvinsert.hParent = NULL;
 tvinsert.hInsertAfter = TVI_LAST;
 tvinsert.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE |TVIF_TEXT;
 tvinsert.item.hItem = NULL;
 tvinsert.item.state = 0;
 tvinsert.item.stateMask = 0;
 tvinsert.item.cchTextMax = 6;
 tvinsert.item.iSelectedImage = 1;
 tvinsert.item.cChildren = 0;
 tvinsert.item.lParam = 0;
 // top level
 tvinsert.item.pszText = "字符串操作";
 tvinsert.item.iImage = 2;
 HTREEITEM hDad = pTree->InsertItem(&tvinsert);
 tvinsert.item.pszText = "其它操作";
 HTREEITEM hMom = pTree->InsertItem(&tvinsert);
 // second level    
 tvinsert.hParent = hDad;
 tvinsert.item.pszText = "获取字符串长度";
 tvinsert.item.iImage = 3;
 pTree->InsertItem(&tvinsert);
 //以上完成了一个子节点的插入
 tvinsert.item.pszText = "去掉字符串左右的空白字符";
 HTREEITEM hother=pTree->InsertItem(&tvinsert);
 // second level
 tvinsert.hParent=hother;
 tvinsert.item.pszText="去掉字符串左边的空字符";
 tvinsert.item.iImage=7;
 pTree->InsertItem(&tvinsert);
 tvinsert.item.pszText="去掉字符串右边的空字符";
 pTree->InsertItem(&tvinsert);
以上就是给树状控件添加了图标和文字标识,程序运行的界面如图4所示:

图4
看到出来这个效果大家是不是很开心,我当时真的是很开心,不仅仅为了这个程序,更重要的是掌握了这个方法后,我们以后可以随意的编程实现树状控件了。
下面的操作就是各叶子节点建立与各对话框的关联了,为了使操作更具直观性,我们先实现一个较简单的功能,即在界面上添加一个静态文本,让这个静态文本的内容随着叶节点的切换而自动变为相应的内容。
先要为树状控件定义类型,如图5所示

图5
然后建立到TVN_SELCHANGED消息的关联,编辑代码如下:
void Cmytreediao::OnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
 NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
 // TODO: Add your control notification handler code here
 CTreeCtrl* pTree=(CTreeCtrl*)GetDlgItem(IDC_TREE1);
 HTREEITEM hSelcted=pNMTreeView->itemNew.hItem;
 if(hSelcted!=NULL){
  char text[31];
  TV_ITEM item;
  item.mask=TVIF_HANDLE|TVIF_TEXT;
  item.hItem=hSelcted;
  item.pszText=text;
  item.cchTextMax=30;
  VERIFY(pTree->GetItem(&item));
  SetDlgItemText(IDC_STATIC_TEXT1,text);
 }
 *pResult = 0;
}
和序运行后的界面如图6所示,可以看到静态文本的内容已经随着叶节点的切换而改变了。

图6
为了简化操作,我们先只是分别建立三个新的对话框,但是暂不在这三个对话框上进行实际的编程操作,等真正实现了叶节点对应各自对话框的切换以后,我们再对对话框进行编程。
好了,插入三个对话框(如图7所示):IDD_DIALOGgetlen、IDD_DIALOGtrimleft、IDD_DIALOGtrimright。
Style设为Child,Border设为None。

图7
为了区分这三个对话框,我们可以分别在这三个对话框上写上点字符以示区别。同理,要使用这三个对话框,我们要分别建立三个新类:Cdialoggetlen、Cdialogtrimleft、Cdialogtrimright,然后在mytreediao.cpp文件中引用三个头文件
#include "dialoggetlen.h"
#include "dialogtrimleft.h"
#include "dialogtrimright.h"。
做完以上操作后,将程序运行一下。这些操作是不会改变程序界面的,我们只是确认一下到目前为止没有产生错误。
下面我们分别要从几个方面来实现我们的想法
一、在mytreediao.h文件中加入以下二条定义
 CDialog * m_treePages[8];
 CString node_name;
和CImageList m_imageList;放在一起
在构造函数中为m_treePages[8]分配空间,代码如下:
Cmytreediao::Cmytreediao(CWnd* pParent /*=NULL*/)
 : CDialog(Cmytreediao::IDD, pParent)
{
 //{{AFX_DATA_INIT(Cmytreediao)
  // NOTE: the ClassWizard will add member initialization here
 //}}AFX_DATA_INIT
 m_treePages[0]=new Cdialoggetlen;
 m_treePages[1]=new Cdialogtrimleft;
 m_treePages[2]=new Cdialogtrimright;
}
建立节点对应的Dialog
 //建立节点对应的Dialog
 m_treePages[0]->Create(IDD_DIALOGgetlen,this);
 m_treePages[1]->Create(IDD_DIALOGtrimleft,this);
 m_treePages[2]->Create(IDD_DIALOGtrimright,this);
 m_treePages[0]->ShowWindow(SW_SHOW);
 m_treePages[1]->ShowWindow(SW_HIDE);
 m_treePages[2]->ShowWindow(SW_HIDE);
敲入以上代码后,运行一下程序会发现对话框IDD_DIALOGgetlen确实出现了,但是盖住了树状控件,下面我们就要把这个对话框移到合适的位置。
 //把Dialog移到合适位置
 CRect m_rect;
 GetClientRect(m_rect);
 m_rect.left=300;
 m_treePages[0]->MoveWindow(m_rect);
 m_treePages[1]->MoveWindow(m_rect);
 m_treePages[2]->MoveWindow(m_rect);
到此为止,我们应该离成功只差两步了。
我们再到void Cmytreediao::OnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult)
中添加如下代码
UpdateData(true);
 node_name=m_mytree.GetItemText(pNMTreeView->itemNew.hItem);
 //在标题栏显示节点信息
 SetWindowText(node_name);
 //切换面板
 if(node_name=="获取字符串长度"){
  m_treePages[0]->ShowWindow(SW_SHOW);
  m_treePages[1]->ShowWindow(SW_HIDE);
  m_treePages[2]->ShowWindow(SW_HIDE);
 }
 else if(node_name=="去掉字符串左边的空字符"){
  m_treePages[0]->ShowWindow(SW_HIDE);
  m_treePages[1]->ShowWindow(SW_SHOW);
  m_treePages[2]->ShowWindow(SW_HIDE);
 }
 else if(node_name=="去掉字符串右边的空字符"){
  m_treePages[0]->ShowWindow(SW_HIDE);
  m_treePages[1]->ShowWindow(SW_HIDE);
  m_treePages[2]->ShowWindow(SW_SHOW);
 }
 UpdateData(false);
就可以实现在叶节点切换的时候,对应对话框的切换了,程序运行的界面如图8所

示:

图8
第二步,就是在新加的这三个对话框中编程实现对应的操作,这些操作相对较为简单,我写一个单独的文章介绍。

原创粉丝点击