CTreeCtrl控件添加排序功能

来源:互联网 发布:mac上新建文件夹 编辑:程序博客网 时间:2024/06/10 22:36

       由于项目需要,要使用MFC。记录下平时遇到的问题。

       需求是在CTreeCtrl添加按类型,名字排序功能。其中类型是编辑器内部定义的。

       我的做法是通过鼠标右键单击,弹出一个菜单。菜单提供两个选项:按类型、按名字排序。

      这里遇到2个知识点:1. 如何弹出菜单。2. 如何排序

 

1. 弹出菜单:

      由于需要提供其他的特殊功能,我子类化了CTreeCtrl。 通过VS的ClassView找到这个子类,添加WM_CONTEXTMENU消息的响应函数。注意这里并不是添加WM_RBUTTON系列的响应函数。因为右键弹开菜单这个消息并不只是通过右键触发,还可以通过键盘的属性键,shift +f10触发。

  添加新菜单资源,起名为IDR_MENU_SORT,WM_CONTEXTMENU消息的响应函数加入如下代码:

  CPoint point;
   GetCursorPos(&point);
   CMenu menu;
   menu.LoadMenu(IDR_MENU_SORT);
   menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN |
                             TPM_RIGHTBUTTON, point.x, point.y, this);
   menu.DestroyMenu();

  这样就可以弹出菜单了。

  下一步是选择菜单项的响应函数,重载OnCommand函数,在函数内部判断UINT nID = LOWORD(wParam); 为菜单的哪一项,写对应的逻辑。

  完成后会出现一个现象。右键单击不会弹出菜单,双击的时候才会出现。这是因为默认情况下CMainFrame会接收WM_CONTEXTMENU消息,而且WM_CONTEXTMENU通过右键触发的话是由button down 和button up两个消息组成。所以想要让Tree收到这个消息,必须将产生这个消息的前置消息截获并直接返回。解决方法是重载OnRButtonDown函数,并且在里面不进行任何操作。

 

2. 排序

    按名字排序很简单,SortChildren(item);就搞定了,其中item是要排序项的父项。

    如果想制定自己的排序规则,如上文所说的按类型排序,则需要使用SortChildrenCB函数。在我查资料的时候发现很多人使用这个函数的时候遇到些麻烦。下面我说明下用法。

   SortChildrenCB函数的参数是TVSORTCB指针。TVSORTCB包含3个成员:hParent是父项, lParam是要排序tree的指针(需要转换成LPARAM类型),lpfnCompare是比较函数的函数指针。

   关键就是比较函数的书写:int CALLBACK SortByTypeCallBack(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) 函数的定义。

    lParamSort是tree的指针,需要转型。lParam1,lParam2是两个比较项的ItemData。这个ItemData通过SetItemData函数进行设置。很多人看了网上的一些例子,通过这两个参数获得item的名字,结果发现是空串,那是因为网上的例子并不全,给例子的人没有说明这两个参数的意义。正确的做法是设置了SetItemData后,在比较函数中通过对这个参数转型获得itemData,比如上文说的类型。