由于项目需要,要使用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,比如上文说的类型。
这篇博客介绍了如何在MFC的CTreeCtrl控件中添加排序功能,包括通过右键菜单选择排序方式以及自定义排序规则。作者首先讲解了如何弹出菜单,通过子类化CTreeCtrl,响应WM_CONTEXTMENU消息,并处理菜单项的选择。接着,文章详细阐述了如何实现自定义排序,特别是使用SortChildrenCB函数和自定义比较函数SortByTypeCallBack来根据类型进行排序。
6470

被折叠的 条评论
为什么被折叠?



