最近在看《Windows程序设计》一书,其间发现一个小细节:
1. 在非活动窗体上单击鼠标时,Windows将使该窗体成为活动窗体,然后向其发送WM_LBUTTONDOWN消息。
2. 单击窗体上的某一控件时,该控件收到WM_LBUTTONDOWN,但Windows不会使该控件成为焦点控件,而需要程序调用SetFocus来使其获得焦点。
一个事实是,对Windows而言,所有UI元素都是窗口。控件也是窗口,只不过它是主窗口的子窗口;而主窗口同样可以视为Windows的子窗口。
那么,这个处理上的差异暗示了什么呢?
我把这个问题发到CSDN,过了一星期也没得出个所以然。
然而我刚刚想明白了,这个处理上的差异实际上是以下设计思路的体现:
1. 顶级窗体间的切换由Windows控制。
2. 窗体中的控件间的焦点切换由应用程序控制。
在Windows中,应用的单元是进程(或者线程、窗体)。
一个应用程序对外是一个整体,窗体中的控件焦点的切换可视为内部行为,因此Windows不予干涉。
应用程序(窗口)间属于平等和竞争(输入)的关系,因此,活动窗体的切换不能由应用程序控制,而应由Windows进行控制。
根据这个思路,此差异便容易理解了。
在用户期望中,他们希望能够对可见的所有窗体执行鼠标操作,而不论其是否处于活动状态;另外,用户还会希望通过鼠标点击非活动窗体来使窗体进入活动状态从而能够接收键盘输入。因此,Windows的响应便为:先使其转入活动状态,再向其发送鼠标消息。
对于窗体中的控件,我们也许认为Windows可以把控件收到鼠标消息后自动获得焦点作为一个默认行为。这听起来似乎符合我们的常规逻辑,但实际上不然,控件分为“输入”和“非输入”两类,我们只留意到输入性的控件,例如ComboBox、Text等;而忽略了非输入性的静态控件,也就是Label。由于控件是否应在鼠标单击后获得焦点在很大程度上是由控件的性质决定的。因此,此逻辑最适于放置在控件的窗口过程中。