何谓”维持隐喻”?
当你看到一个带有滚动条的窗口显示一份文档的时候,这个窗口实际向你透漏这样的信息:当前你只看到了这份文档的一部分而已,这个窗口,你可以理解为一个观察口,用来查看整份文档。重新调整窗口大小这一行为,实际上是个隐喻:客户区的原点将始终维持在客户区的左上角。但是,如果我们从顶部或者从左侧进行窗口大小调整时,这个隐喻就会被打破。
例如,假设文档的第一行是第十行。如果用户抓住窗口的顶部边缘,并向上调整一行尺寸(以尝试查看第9行),默认行为是保留原点,使第10行保持在窗口的顶部。视觉效果是窗口向上滚动一个行,从而阻止了用户查看第9行的尝试。
这是用户很少有意识地注意到的滚动条的精妙之处之一,但是当它不起作用时,给人的印象是计算机总是无法把每件事情做对。
修复方法
下面,让我们来修复这个滚动的行为,使得观察口这个隐喻得以维持。我们的修复过程将会分为几个步骤来进行。第一步,我们先将隐喻尽可能的保持,在[OnWindowPosChanging]消息处理例程中添加如下的代码。
现在我们来运行修改后的程序。将滚动条移动到中间的某个位置,然后向上或者向下拖动窗口的顶部边缘。我们可以注意到,现有的行在屏幕中并没有移动,调整窗口顶部边缘操作只是显示或隐藏顶部的行。这个行为,和我们调整窗口底部边缘时的行为是一样的。
以上代码有两个问题
但是,以上代码有一些错误。下面我们来逐条讲解。首先,它做的太过了,它的实现方法是抓住窗户并将它在屏幕上拖动。我们观察到它仍然试图保持上面所说到的观察口的隐喻(这似乎更糟了:糟糕的程序取决于鼠标移动的速度。如果禁用[在拖动时显示窗口内容]这一选项的话,拖动的痕迹会更明显。)。这可能是不希望的。
第二,我们可以观察到非常明显的窗口闪烁。
接下来,我们将会逐一解决上面所说的两个问题。第一个问题是很容易解决的。首先,我们只在窗口正在同时移动和调整大小的时候进行处理。这样可以防止窗口简单的移动就触发我们的处理代码。
现在,如果我们抓住窗户并四处移动,我们的维持隐喻的代码不会被执行,因为窗口的大小没有变化。但是,如果我们最大化窗口,隐喻代码就会启动。但这个小问题可以很容易地被修正:仅当窗口的上边缘发生变化而下边缘没有变化时才执行隐喻代码。
但是,我们仍然还存在窗口闪烁的问题。在解决此问题之前,我们将需要对WM_NCCALCSIZE消息进行更加深入的了解。
总结
我们关注细节,我们讨厌细节,我们热爱细节。