如何正确地在对话框中设置焦点
在一个对话框程序中设置输入焦点,可不仅仅是简单地调用SetFocus那么简单。
在一个对话框中,会维护一个所谓的”默认按钮”的概念,这个默认按钮始终是一个按下式按钮(Push Button)。一般情况下,默认按钮会绘制上一层外框用来指明:当用户按下回车键时,此按钮会被点击并执行相应的事件处理程序。但是,请注意了,这个概念和一个拥有输入焦点的控件可不一样。
举个例子,我们打开开始菜单的运行对话框。我们可以观察到[确定]按钮被设置成了默认按钮,从外观上来看,它被添加了一层外框,但是此时拥有输入焦点的控件是输入框。你可以直接在输入框中输入文本,直到按下回车按钮,这次按下会激发默认按钮的动作,也就是这里的[确定]按钮。
如果你按下Tab按键进行对话框控件焦点导航,请仔细观察下默认按钮的行为。当对话框的输入焦点移至一个按下式按钮时,这个按钮会变成一个新的默认按钮。但是如果焦点被移动到一个非按下式按钮,则[确定]按钮又重新变成了默认按钮,经过我这么一说,你是否有点神奇的感觉呢?
对话框管理器会在内部记录下对话框创建之初的默认按钮,当输入焦点切换至一个非按下式按钮时,它会使用早前记录下来的内部信息来将默认按钮还原。
你可以通过向对话框发送DM_GETDEFID消息来询问对话框当前默认按钮是哪一个,类似的,你也可以通过发送DM_SETDEFID来设置默认按钮。
(请注意,DM_GETDEFID消息的返回值会将控件ID保存到DWORD的低字中,而将标志信息保存到高字中。所以,这也侧面告诉我们,将对话框控件ID从16位扩展到32位,并不会带来任何的好处)
根据DM_SETDEFID函数的文档描述,不小心直接使用默认ID会导致奇怪的情况,例如会出现一个带有两个默认按钮的对话框。幸运的是,通常你不需要改变对话框的默认按钮ID。
一个更大的问题是使用SetFocus在对话框上移动焦点。如果你这样做的话,你会跳过对话框管理器,而直接和窗口管理器进行交互。这意味着,你可能无意中创建了这样一个”不可能发生的”的情况:对话框上的一个按下式按钮拥有了输入焦点,但是这个按钮却不是默认按钮。有点糊涂了?请回想我们上面提到的运行对话框。
为了避免这种情况,请不要使用SetFocus来修改对话框上的输入焦点,而是使用WM_NEXTDLGCTL消息,具体代码如下图所示:
在WM_NEXTDLGCTL消息的技术文档中有提到,DefDlgProc函数会处理WM_NEXTDLGCTL这个消息,它会更新对话框管理器中保存的所有内部状态,并决定将哪个按钮设置为默认按钮,反正,就是一些非常有用的内部操作。
现在,理解了上面所说的,你就可以像一个专家一样设置对话框焦点了,不会再发生哪些古怪的行为,例如没有默认按钮,或者更糟的,有多个默认按钮。
总结
之前做对话框程序,都是无脑使用SetFocus,现在看来,还真是误用了。
我应该早一点读到这篇文章!(害。。。)
最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《How to set focus in a dialog box》
最近我写了个东西
正如你们所知道的,拓扑梅尔智慧办公平台(Topomel Box)是一款绿色软件,主要面向经常使用电脑的朋友。它提供了各种提升办公效率的小功能,同时操作上尽可能地简单方便。
我想:你值得拥有。
- 下一篇: 为什么共享数据分区是一个安全漏洞
- 上一篇: 关于DS_CONTROL风格的讲解
相关推荐
- 在单选按钮上实现双击效果
- Posted on 01月01日
- Visual C++ 2005 可以生成清单信息了
- Posted on 03月11日
- 说说滚动条的两种类型
- Posted on 02月22日
- 为什么RECT结构体被设计为开区间
- Posted on 12月15日
评论已关闭。