树控制的应用技巧示例

来源:互联网 发布:知乎 丁磊和马云 编辑:程序博客网 时间:2024/05/21 17:32

 

这里仍以基于对话框演示实例来具体介绍树控制及其和图像列表相结构的应用技巧:

    通过“FILE->NEW->PROJECTS->MFC AppWizard(EXE)”建立名为VCTREE的工程,在建立过程中选择基于对话框(Dialog based)的应用;将对话框中的默认控件删除,并将所有对话框属性中的Language域设置为Chinese(P.R.C.),以使应用程序支持中文;建立两个图标IDI_PMIDI_CJ,用来表示图标的选中和非选中状态,对于每个图标都应建立32X3216X16两种大小,以保证程序的需要;在对话框窗口中添加树控制对象(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::OnInitDialog()

    {    CDialog::OnInitDialog();

    ......//原来其它代码

    // 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::OnAdd()

    {    //增加子项功能函数

    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::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;

    }

7、树视的演练技巧

树视的应用技巧在使用树视时,其方法与树控制基本相同,只不过树视是在窗口中来实现的而树控制是在对话框中实现,树视的各种功能是通过菜单来实现的而树控制是通过按钮等方式来实现的,树控制需要在对话框中创建树控制控件而树视直接占据整个窗口,在设计过程中只要将按钮和树控制设计过程变为菜单设计,并注意在功能函数是在类向导中是通过菜单命令来操作,同时在每个功能函数前面增加取得列表视引用的命令(CTreeCtrl& TreeCtrl = GetTreeCtrl()),而其余数据结构和代码均不需要修改,实现起来比较容易。笔者实现的树控制和视程序的运行结果如下:


              树视演练结果示例