本人自己开发了一个GUI,现在在刷新上有个问题处理不好,想借鉴一下windows操作系统是如何处理这个问题的。
    例如在桌面上有3个窗口A、B、C,它们的在桌面上的位置为A(100,100,300,300)、B(400,100,600,300)、C(200,50,500,350),C窗口在A、B窗口之上。
    问题1:当A、B窗口上图像有刷新时,它们只会刷新没有被C窗口遮住的地方,window是是如何实现这个功能的?它的原理是什么?
    问题2:当把C窗口关闭的时候,A和B窗口是不是整个窗口都重画了还是只重画了被C窗口遮住的部分?这个问题扩展一下,是不是桌面上每个窗口关闭时,其它窗口都收到重画的消息?如何判断哪个窗口需要重画哪个窗口不需要重画?    请问有了解这方面的原理的吗?或有什么书讲这个的给推荐一下。谢谢!

解决方案 »

  1.   

    书没看过,接触过一些OpenGL方面的东西,想象一下Windows的做法吧:问题1:
    最终我们在显示屏上看到的都是经过显卡渲染出来的,windows的GDI及kernel也最终也会通过OpenGL或者DirectDraw之类的接口进行显示,所有的窗口经过一系列的运算,就获得了我们能够看到的具有层叠效果的窗口。
    所有GDI下windows的窗口重绘时都会向windows发出重绘消息,但你必须提供HWND,通过HWND,windows可以获得当前所有窗口的信息,包括是否隐藏、窗口大小、Z-Order、当前windows的主题风格等等,从这些信息得出我们最终的显示结果算起来应该不是很难。问题2:
    C关闭时只是通知了windows系统,根据C的HWND以及所有窗口的信息,windows会检测出哪些窗口需要重绘,然后向需要重绘的窗口发出重绘消息。具体的算法应该比较容易吧:
    1. 所有隐藏的窗口都不会重绘
    2. 所有最小化的窗口都不会重绘
    3. 根据当前windows的分辨率及所有窗口的Rect计算得出所有需要重绘的HWND
    3.1 按照Z-Order的顺序从最顶层依次向最底层计算,最底层肯定是桌面
    3.2 最笨的方法就是所有的窗口全部重绘
    3.3 结合自己系统的特点可进行有针对性的优化
    4. 向所有的需要重绘的HWND发送重绘消息
      

  2.   

    用InvalidateRect()可以刷新某一Rect内的区域用求交, 求并,IntersectRect(),UnionRect()  刷新Rect区域
      

  3.   

    问题1:当A、B窗口上图像有刷新时,它们只会刷新没有被C窗口遮住的地方,window是是如何实现这个功能的?它的原理是什么?
    --------------------------------
    这个问题涉及windows如何计算无效区域和裁减区域的问题,具体的原理你可以看“windows图形编程”这本书中的第五章,windows更新区域的一些说明,以及GDI+程序设计这本书中的第七章裁减和失效,这部分内容对于如何理解windows如何高效处理界面有很好的注解    问题2:当把C窗口关闭的时候,A和B窗口是不是整个窗口都重画了还是只重画了被C窗口遮住的部分?这个问题扩展一下,是不是桌面上每个窗口关闭时,其它窗口都收到重画的消息?如何判断哪个窗口需要重画哪个窗口不需要重画?
    ------------------------------------------------------------------------
    这个问题么还是一句话,取决于当时被标记为无效区域的部分是哪些,按照正常理解,只有被遮住的部分会被标为无效区域,需要重绘。扩展的问题,负责管理每个窗口重绘的是windows,他把所有被标为无效区域的都重新计算一个需要绘制的最小矩形,在下一次wm_pain消息处理的时候进行重绘,并非分别处理
    InvalidatedRect 
    使一个矩形无效,需要重绘该矩形,在该矩形做一个重绘的标记,当下一次WM_PAINT发出的时候,该矩形被重绘.
    使显示矩形区无效,WM_PAINT会对无效的区域重画
    函数中的参数TRUE表示系统会在你画之前用背景色将所选区域覆盖一次,默认背景色为白色,可以通过设置BRUSH来改变背景色。  UpdateWindow
    强制发出一个WM_PAINT消息 
    会发送一条WM_PAINT,但不进入消息队列,呼叫立即更新窗口  
    只向窗体发送WM_PAINT消息,在发送之前判断GetUpdateRect(hWnd,NULL,TRUE)看有无可绘制的客户区域,如果没有,则不发送WM_PAINT   如果希望立即刷新无效区域,可以在调用InvalidateRect之后调用UpdateWindow,如果客户区的任一部分无效,
    则UpdateWindow将导致Windows用WM_PAINT消息调用窗口过程(如果整个客户区有效,则不调用窗口过程)。
    这一WM_PAINT消息不进入消息队列,直接由WINDOWS调用窗口过程。窗口过程完成刷新以后立刻退出,
    WINDOWS将控制返回给程序中UpdateWindow调用之后的语句。ValidateRect(HWND)使窗口有效,在下一个WM_PAINT消息发出的时候,把该矩形从需要更新的标记清除,使之不需要更新