treectl 的使用

(一)树控制的主要功能 树控制和视(Tree Control&View)主要用来显示具有一定层次结构的数据项,如资源管理器中的磁盘目录等,以供用户在其中进行各种选择。
 
       树控制中的每个数据项包括数据项名称的文本字符串和用于表示该数据项的图像,每个数据项下面均可包含各种子项,整个结构就象目录树一样。对于包含各种子项的数据项,可通过鼠标双击来展开或合拢,这可以通过控制树的不同风格来实现树控制的不同显示形态。
       这些风格主要包括:
       TVS_HASLINES表示用连线来连接父项和它下面的各个子项,这可以使树的显示层次结构更加清晰,但在无父项的各子项之间并没有连线;
       TVS_LINESATROOT表示在无父项的各子项即根下面的各子项之间存在连线;
       TVS_HASBUTTONS表示在带有子项的父项前面增加一个带“+”或“-”的按钮,这使得用户也可以通过单击这个小按钮来实现子项的展开和合拢,当存在子项时,按钮的初始状态为“+”,当子项被展开时,按小按钮由“+”变为“-”号,当子项合拢时,小按钮由“-”变为“+”号,这一风格同样对于根项无效,如果需要可通过组合TVS_LINESATROOT风格来实现;
       TVS_EDITLABELS表示允许让用户单击具有输入焦点的数据项来修改其名称。
       对于树控制,MFC中也以两种形式来封装,即树控制(CTREECTRL)和树视(CTREEVIEW),来满足用户的不同需求,对于一般要求的用户如在对话框中应用,使用树控制比较方便,而对于具有较高要求的用户,在使用树视时还具有视窗口的各种方便特性,可以更好地满足文档/视结构的要求。当在窗口中使用树视时,树视会占满两个窗口的客户区域并自动随窗口的框架结构的调整而调整,并能够很好地处理诸如菜单、加速键和工具条中的各种命令消息。在使用树视时只要利用其成员函数CtreeView取得其一个引用,就可以象树控制一样方便地应用:CtreeCtrl &treeCtrl = GetTreeCtrl()
 
(二)树控制的对象结构
 
1、树控制的建立方法
CtreeCtrl&treeCtrl 建立树控制对象结构
Create 建立树控制并绑定对象
树控制CTreeCtrl::Create的调用格式如下:
BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
其中参数dwStyle用来确定树控制的类型;rect用来确定树控制的大小和位置;pParentWnd用来确定树控制的父窗口,通用是一个对话框并且不能为NULL;nID用来确定树控制的标识。
树控制的风格可以是下列值的组合: TVS_HASLINES 表示树控制在各子项之间存在连线; TVS_LINESATROOT 表示树控制在根项之间存在连线; TVS_HASBUTTONS 表示树控制视在父项左侧存在展开合拢控制按钮; TVS_EDITLABELS 表示可以控制鼠标单击修改树项的名称; TVS_SHOWSELALWAYS 表示选中项即使在窗口失去输入焦点时仍然保持选中状态; TVS_DISABLEDRAGDROP表示禁止树控制发送TVN_BEGINDRAG消息
 
2、树控制的属性类树控制属性类包括:
取得树控制中项数GetCount;
取得树控制中项相对于父项的偏移值GetIndent;
取得树控制图像列表控制句柄GetImageList;
设置树控制图像列表控制句柄SetImageList;
取得匹配下一个树项GetNextItem;
判断给定树项是否包含子项ItemHasChildren;
取得树项子项GetChildItem;
取得下一个同属树项GetNextSiblingItem;
取得前一个同属树项GetPrevSiblingItem;
取得父树项GetParentItem;
取得第一个可视树项GetFirstVisibleItem;
取得下一个可视树项GetNextVisibleItem;
取得前一个可视的树项GetPrevVisibleItem;
取得被选中的树项GetSelectedItem;
取得根树项GetRootItem;
取得树项的属性GetItem;
设置树项的属性SetItem;
取得树项的状态GetItemState;
设置树项的状态SetItemState;
取得与树项关联图像GetItemImage;
设置与树项关联图像SetItemImage;
取得树项文本GetItemText;
设置树项文本SetItemText;
取得树项编辑控制句柄GetEditControl等。
 
  3、树控制的操作方法树控制的操作方法包括:
插入一个树项InsertItem;
删除一个树项DeleteItem;
删除所有树项DeleteAllItems;
展开或合拢树项的子项Expand;
选中特定树项SelectItem;
选择一个树项作为第一个可视树项SelectSetFirstVisible;
编辑一个可视的树项EditLabel;
排序给定父树项的子树项SortChildren等。
 
(三)树控制的数据结构在使用树控制时需要了解两个非常重要的数据结构:TV_ITEM和TV_INSERTSTRUCT。
      
       前一个数据结构是用来表示树控制的树项信息,后一个数据结构是用来定义将树项增加到数据控制中所需要的数据内容。
       另外,还需要NM_TREEVIEW、TV_DISPINFO和TV_HITTESTINFO三个数据结构,这几个数据结构的定义方法如下:
 
①基本数据项结构 typedef struct _TV_ITEM {
                               UINT mask; //结构成员有效性屏蔽位
                               HTREEITEM hItem; //数据项控制句柄
                               UINT state; //数据项状态
                               UINT stateMask; //状态有效性屏蔽位
                               LPSTR pszText; //数据项名称字符串
                               int cchTextMax; //数据项名称的最大长度
                               int iImage; //数据项图标索引号
                               int iSelectedImage;//选中数据项图标索引号
                               int cChildren; //子项标识
                               LPARAM lParam; //程序定义的32位数据 } TV_ITEM, FAR *LPTV_ITEM;
 
②插入树项结构 typedef struct _TV_INSER TSTRUCT {
                            HTREEITEM hParent; //父项控制句柄
                            HTREEITEM hInsertAfter; //插入树项的位置
                            TV_ITEM item; //数据项的结构 } TV_INSERTSTRUCT, FAR *LPTV_INSERTSTRUCT;
 
其中插入的位置如果是TVI_FIRST 或TVI_LAST ,则分别插入到树控制的最前面或最后面,如果是TVI_SORT ,则插入的树项自动插入到合适的位置。
 
  ③树控制通知消息结构 typedef struct _NM_TREEVIEW {
                                          NMHDR hdr; //通知消息句柄
                                          UINT act ion; //通知消息标志
                                          TV_ITEM itemOld; //原来的数据结构
                                          TV_ITEM itemNew; //新的数据结构
                                          POINT ptDrag; //拖动指针 } NM_TREEVIEW;
 
④取得或设置数据结构 typedef struct _TV_DISPINFO {
                                        tvdi NMHDR hdr; //通知消息控制句柄
                                        TV_ITEM item; //数据项结构 } TV_DISPINFO;
 
⑤指针测试数据结构 typedef struct _TVHITTESTINFO {
                                     tvhtst POINT pt; //客户区域屏幕坐标指针
                                     UINT flags; //存放测试结果的变量
                                     HTREEITEM hItem; //测试的数据项结构 } TV_HITTESTINFO, FAR *LPTV_HITTESTINFO;
 
其中flags测试结果可以是如下值:
                                   TVHT_ABOVE 在客户区域上面
                                   TVHT_BELOW 在客户区域下面
                                   TVHT_NOWHERE 在客户区域中并在最后一项下面
                                   TVHT_ON ITEM 在与树项关联的位图或标签内
                                   TVHT_ON ITEMBUTTON 在与树项关联的按钮上
                                   TVHT_ON ITEMICON 在与树项关联的位图上
                                   TVHT_ON ITEMINDENT 在与树项关联的联线上
                                   TVHT_ON ITEMLABEL 在与树项关联的标签上
                                   TVHT_ON ITEMRIGHT 在树项的右侧区域中
                                   TVHT_ON ITEMSTATEICON 在用户定义的状态图标上
                                   TVHT_TOLEFT 在客户区域的左侧
                                   TVHT_TORIGHT 在客户区域的右侧
 
(四)树控制的应用技巧示例这里仍以基于对话框演示实例来具体介绍树控制及其和图像列表相结构的应用技巧:     
       1、 通过“FILE->NEW->PROJECTS->MFC AppWizard(EXE)”建立名为VCTREE的工程,在建立过程中选择基于对话框(Dialog based)的应用;
       2、将对话框中的默认控件删除,并将所有对话框属性中的Language域设置为Chinese(P.R.C.),以使应用程序支持中文;
       3、建立两个图标IDI_PM和IDI_CJ,用来表示图标的选中和非选中状态,对于每个图标都应建立32X32和16X16两种大小,以保证程序的需要;
       4、在对话框窗口中添加树控制对象(TREE CONTROL),并设置五个按钮“增加|删除|查看|排序|关闭”,其对应标识分别如下: 控制名称 标题名称 标识符号 树控制 IDC_TREECTRL 按钮 增 加 IDC_ADD 删 除 IDC_DEL 查 看 IDC_VIEW 排 序 IDC_SORT 关闭 IDOK ;
       5、选中树控制控件,选择“VIEW->ClassWizard->Memory Variables。DC_TREECTRL 引入成员变量,其变量类型为: 变量名 种类 变量类型 m_TreeCtrl Control CTreeCtrl 同时利用“MESSAGES MAP”为各命令按钮增加控制功能函数;
      6、然后在代码文件VCTREEDlg.CPP中分别加入如下控制代码:
 
  (1)在文件开始处增加图像列表定义 CImageList Cil1,Cil2;//大小图标像列表
 
(2)在初始化文件开始处增加代码
BOOL CVCTREEDlg::On InitDialog() {
CDialog::On InitDialog(); ......//原来其它代码
// TODO: Add extra initialization here // 此处开始增加代码
CVCTREEApp *pApp=(CVCTREEApp *)AfxGetApp();//创建图象列表
Cil1.Create(16,16,ILC_COLOR,2,2);
Cil1.Add(pApp->LoadIcon(IDI_PM));
Cil1.Add(pApp->LoadIcon(IDI_CJ));
m_TreeCtrl.SetImageList(&Cil1,TVSIL_NORMAL); //设置图象列表
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);//设置风格
char * CJ[4]={"玉溪卷烟厂","云南卷烟厂","沈阳卷烟厂","成都卷烟厂"};//根数据名称
char * PM[4][5]={ {"红梅一","红梅二","红梅三","红梅四","红梅五"},//产品数据项
                            {"白梅一","白梅二","白梅三","白梅四","白梅五"},
                            {"绿梅一","绿梅二","绿梅三","绿梅四","绿梅五"},
                            {"青梅一","青梅二","青梅三","青梅四","青梅五"}};
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::On Add() { //增加子项功能函数
HTREEITEM hSel=m_TreeCtrl.GetSelectedItem();//取得选择项句柄
if(hSel==NULL) return;//无任何选项则返回
static int nAddNo=100;//编号大于100为新增数据
TV_INSERTSTRUCT TCItem;//定义插入项数据结构
TCItem.hParent=hSel; //设置父项句柄
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::On Del() { //删除子项功能函数
HTREEITEM hSel=m_TreeCtrl.GetSelectedItem();//取得选项句柄;
 if(hSel==NULL) return;//无任何选项则返回
if(m_TreeCtrl.ItemHasChildren(hSel))//判断是否有子项
if(MessageBox("厂家下存在品名,一同删除?","警告",MB_YESNO)==IDNO)
return;
m_TreeCtrl.DeleteItem(hSel); }


CTreeCtl的使用的一点总结:
一、设置与tree control控件相关联的图片列表
 CImageList imageList;
 CTreeCtl treeCtl;
 imageList.Create(IDB_BITMAP, 16, 1, RGB(255,255,255));
 treeCtl.SetImageList( imageList, TVSIL_NORMAL );
二、tree control标签基本拖动的实现
    (参考vckbase中,树型控件拖动的完美实现 作者:一块三毛钱 http://www.vckbase.com/document/viewdoc/?id=340)
    1、拖动时,控件会发送TVN_BEGINDRAG消息,添加该消息响应函数。在函数中创建拖动标签的一副图象。
      CImageLis* image = treeCtl.CreateDragImage( hItem );
      注:该函数只能在CTreeCtrl带位图的时候才起作用
       然后调用CImageList的BeginDrag开始拖动:
      image->BeginDrag( 0, CPoint(0,0) );
       调用CImageList的DragEnter显示拖动的图象:
      image->DragEnter( pWndLock, point );
      SetCapture();   //捕捉鼠标
    2、处理WM_MOUSEMOVE消息
             CImageList::DragMove(point);  //在拖动过程中移动被拖动的图片
       调用SelectDropTarget高亮显示移动过程中图象经过的项。
      CImageList::DragShowNolock( false );  //隐藏图象列表
      treeCtl.SelectDropTarget( item );
      CImageList::DragShowNolock( true );    //恢复图象列表的显示
    3、处理WM_LBUTTONUP消息
             CImageList::DragLeave( hWnd );  //解锁所指窗口并隐藏图片,完成窗口更新
             CImageList::EndDrag();       //Ends a drag operation
      ReleaseCapture();             //释放鼠标
      image->Destroy();
             m_treeCtl.SelectDropTarget( NULL );
    4、拷贝所托的标签以及其子标签到指定位置
 // 拷贝条目
 HTREEITEM CopyItem(HTREEITEM hItem, HTREEITEM hParent,HTREEITEM hInsertAfter)
 {
  TVINSERTSTRUCT insertStruct;
  WCHAR text[50] = L"";
  HTREEITEM hNewItem;

  //得到源条目的信息
  insertStruct.item.hItem = hItem;
  insertStruct.item.mask = TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
  m_treeCtl.GetItem( &insertStruct.item );
  m_treeCtl.GetItemText( hItem, text, 50 );
  insertStruct.item.pszText = text;
  insertStruct.item.cchTextMax = 50;
 
 
  //将条目插入到合适的位置
  insertStruct.hParent = hParent;
  insertStruct.hInsertAfter = hInsertAfter;
  insertStruct.item.mask = TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_TEXT|TVIF_PARAM;

  hNewItem = m_treeCtl.InsertItem( &insertStruct );
  return hNewItem;
 }
 //拷贝分支
 HTREEITEM CopyBranch(HTREEITEM htiBranch, HTREEITEM htiNewParent, HTREEITEM htiAfter)
 {
  HTREEITEM hNewItem = CopyItem( htiBranch, htiNewParent, htiAfter );
  HTREEITEM hChildItem = m_treeCtl.GetChildItem( htiBranch );
  while( hChildItem != NULL )
  {
   CopyBranch( hChildItem, hNewItem, htiAfter );
   hChildItem = m_treeCtl.GetNextSiblingItem( hChildItem );
  }
  return hNewItem;
 }


你可能感兴趣的:(控件)