滚动条

来源:互联网 发布:java 商城 小程序 编辑:程序博客网 时间:2024/04/27 16:25

 以前做过程序自己处理滚动条,为屏幕无效区的更新和屏幕的闪烁花了不少功夫,还使用了双缓冲。近两天看了一下CScrollView类,发现这些工作都帮你做好了,会省不少事。于是想研究一下它的实现方法,研究结果表明其实就是普通VC书籍上讲解的滚动条处理方式,却让我对VC无效区的处理和坐标转换有了更深入的认识。

    对于滚动条点击或拖动以后导致滚动条变量信息的改变就不说了,逻辑很简单,下面主要来分析点击或拖动以后的处理。

    比如我们点击了一下垂直滚动条的向上按钮,这时,窗口要向下滚动一行,我们现在就是要实现这个功能。滚动窗口有一个特性,就是窗口的大部分区域信息没有改变,只是位置下移了。系统有一个ScrollWindow函数,专门用于窗口信息的移动,底层实现就是把内存中的数据直接复制到相应位置,而不需要重新绘制,并将滚动后的那块区域设为有效区,这样就减少无效区的范围。然后,窗口最上面的一行需要更新,这时将其设为无效区,重新绘制该区域就可以了。

     绘制无效区就出现问题了,因为我们将窗口移动,如果只是把窗口最上面一行重新绘制,那就会使第二行和第一行的显示相同,没有达到绘制紧贴窗口上的一行的目的,该如何处理呢?这就前涉到坐标变换的问题。首先要明确,你在DC上进行的任何操作都是针对逻辑坐标的,并且是在“窗口”坐标上进行的,而具体哪些内容被显示到屏幕上,取决于“视口”(viewport)坐标系。窗口坐标和视口坐标有一个对应关系,可以看作两个原点重叠,注意,原点不一定是(0,0)点。对于窗口上的坐标值,要转换为视口坐标值,首先是减去窗口原点值,然后乘以比例因子,然后加上视口原点值得到的。屏幕上显示窗口的左上角始终是视口的(0,0)点,对于坐标转换的多种模式,请参看相关书籍。

     如果你覆盖CScrollview的OnPaint函数,并在其中进行绘图操作,就会发现滚动条不能正常工作。如果不覆盖,而直接在OnDraw中进行绘图操作,就会如愿以偿,原因何在呢?其实CScrollView中的OnPaint函数默认调用了OnDraw函数,并在OnDraw之前有这么一行代码:OnPrepareDC(&dc)。这一句是关键所在,通过debug跟踪代码发现,其中有一行SetViewportOrg起到了关键作用。这个函数用来设置视口的原点,通过将视口原点上调,我们就会在同一区域绘制出本来显示在其之下的内容,这样就达到了滚动的目的。其实我们也可以通过SetWindowOrg的方法改变窗口原点,要记住和SetViewport的设置恰恰相反。

      通过以上分析,你应该对滚动条的实现逻辑和坐标变换比较清楚了吧?

原创粉丝点击