当前位置: 首页 > 图文教程 > 开发语言 > VC++ > 如何锁定 ListView 的栏目头宽度

VC++
在类VC的界面实现中加入目录树
软件换肤技术在 BCB 中的实现
利用非模窗口生成MDI介面
报表输出轻松搞定
Windows 中不规则窗体的编程实现
解说Win32的窗口子类化
使用测试优先方法开发用户界面
一个简单的登录对话框的实现
一个简单的日记本程序
从资源中加载皮肤
一个在RichEdit中添加表情图象的类
ActiveSkin 4.3 软件换肤在VC中的实现
一种另类“关于(About)”对话框的动态显示方法
对话框打印预览及打印
关于如何换肤、子类化的解决方案
制作 MSN、QQ 的消息提示窗口
如何对 BCGControlBarPro 进行换肤
定制个性化的对话框窗口类
改变窗口中的光标形状
更新MFC中的视图,跟踪.NET Framework中的事件

VC++ 中的 如何锁定 ListView 的栏目头宽度


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-30   浏览: 114 ::
收藏到网摘: n/a

如何锁定 ListView 的栏目头宽度


编译:NorthTibet

下载源代码


    世界之大,真是无其不有。Windows 应用程序的GUI标准明确规定了 ListView 栏目头(Column Header)的宽度必须是可调整的,这本来是专门为用户考虑而设计的控制特性,可是偏偏就有用户拒绝这样的特性。作为技术人员,用户的需求是很难拒绝的。 尽管这明显是一种“非典型性需求”。本文将通过一个实例来示范如何实现 ListView Column Header 宽度的锁定。
    ListView 及其 Column Header 实际上都是 Windows 通用控件(Comctl32.dll) 的一部分。所以查一查 MSDN 中与“Header Control”相关的控件资料不难发现,栏目头的锁定与否与几个 Windows 的通知消息密切相关,这几个消息分别是 HDN_TRACK、HDN_BEGINTRACK 和 HDN_ENDTRACKA。其中 HDN_BEGINTRACK 是本文要特别关照的一个。当用户在栏目头上拖拽鼠标时,如果位置正好在改变宽度的分割条上,则栏目头控件会向其父窗口发送一个 HDN_BEGINTRACK 通知消息。为了实现栏目头宽度的锁定,就必须搞掂这个通知消息。不能将它传递到父窗口,但是,这个消息与 Windows 中形形色色的其它通知消息一样,有两个版本:一个版本是 HDN_BEGINTRACKW,专门用于宽字符和 Unicode 字符集;另一个版本是 HDN_BEGINTRACKA,专门用于 ANSI 字符集。这两个版本的使用方法可以从公共控件的头文件 commctrl.h 中获取:

// From commctrl.h#ifdef UNICODE#define HDN_BEGINTRACK HDN_BEGINTRACKW#else#define HDN_BEGINTRACK HDN_BEGINTRACKA#endif 
    所以在实现对消息的 HDN_BEGINTRACK 处理时,实际上是根据 UNICODE 的取值实现对 HDN_BEGINTRACKA 或 HDN_BEGINTRACKW 的处理。那么 Header Control 到底是发送的哪一个消息呢?在这里必须明白:Header Control 是 Windows 通用控件的一部分,它的实现都在 comctl32.dll 动态链接库中。由于这个 DLL 已经被编译成可执行代码,因此在工程中修改 UNICODE 的设置将无济于事。如何知道栏目头控件发送哪一个版本的通知消息呢?是 A 版本还是 W 版本?
    为了找到答案,我们必须求助一个经常被遗忘的消息 WM_NOTIFYFORMAT。一般控件第一次被创建时,都要向父窗口一个消息询问父窗口需要哪个版本的通知消息。然后父窗口返回 NFR_ANSI 或 NFR_UNICODE。如果父窗口不处理 WM_NOTIFYFORMAT,那么这个消息将根据父窗口或对话框本身的首选项被传递到 Windows 的 DefWindowProc 消息处理例程进行默认处理。默认为 UNICODE。因此,要知道通知消息的版本,必须处理 ListCtrl 的 WM_NOTIFYFORMAT。为了确认父窗口的返回值,你可以做一个试验便明白了。
    如果你不想处理 WM_NOTIFYFORMAT 消息,那么完全可以通过双双实现 HDN_BEGINTRACKA 和 HDN_BEGINTRACKW 通知消息的处理来简化问题的解决方案,同时这种方法也更可靠和通用。此时代码将同时支持 ANSI 和 Unicode。本文附带的例子程序示范了这种方法的实现。如图一所示:


图一 锁定栏目头宽度

    实现代码很简单,Header 控件发送 HDN_XXX 到父窗口(ListCtrl),在 MFC 中可以利用消息反射来处理 Header 控件的通知消息。因为“可锁定栏目头”特性本身更趋向于 Header 控件的属性,而不是 ListCtrl 的属性。如果你不用 MFC ,那么就得处理 ListCtrl 中的通知消息。例子程序使用了消息反射机制,在 Header 控件的消息映射使用 ON_NOTIFY_REFLECT,也就是该写虚拟成员函数 OnChildNotify:
BOOL CLockableHeader::OnChildNotify(UINT msg, WPARAM wp, LPARAM lp, LRESULT* pRes){ NMHDR& nmh = *(NMHDR*)lp; if (nmh.code==HDN_BEGINTRACKW || nmg.code==HDN_BEGINTRACKA)	return *pRes=TRUE; ......}
    因为 OnChildNotify 是虚函数,所以没有必要具备消息映射入口。只要实现此函数即可。在任何应用中,Header 发送的消息非此即彼,不会两者都发送。不管怎样,所发送的通知消息在到达父窗口之前都会被吃掉。也就是说,消息处理总是返回 TRUE,是否锁定栏目头的宽度通过一个标志来控制:应用程序通过 Lock 来修改标志的