有时,在有大量图片或者复杂的界面下,会出现界面闪烁。这是由于windows默认在绘制界面前会用背景色清空,然后重绘。
因为默认背景色一般是白色的,当重绘速度慢时,看起来界面就在闪烁了。
那有没有在不提高界面绘制速度的情况下,防止闪烁呢,常用的办法就是启用双缓冲机制。
双缓冲绘制,就是在内存预先绘制好图形,再拷贝到界面上。中途不再清白背景。
delphi的wincontrol组件提供了双缓冲机制,所以从该组件继承的比如窗体,各类windows控件都有双缓冲绘制功能。
但默认情况下双缓冲绘制是关闭的,在手工设置 DoubleBuffered 属性为true后双缓冲绘制机制开启。无需添加其他代码。
下面就delphi的双缓冲原理做一简单的注释。(为简单起见,用屏幕上的和内存中的来表示双缓冲的两个部分)
procedure TWinControl.WMPaint(var Message: TWMPaint); var DC, MemDC: HDC; MemBitmap, OldBitmap: HBITMAP; PS: TPaintStruct; begin if not FDoubleBuffered or (Message. DC <> 0) then //查看DoubleBuffered属性和指定消息值,如果双缓冲关闭或者dc值有效,那么直接绘制图像 注★ begin if not (csCustomPaint in ControlState) and (ControlCount = 0) then inherited else PaintHandler(Message); //调用具体过程来重画到Message指定的设备上(内存中的或者屏幕上的) end else begin //进入双缓冲处理 DC := GetDC(0); MemBitmap := CreateCompatibleBitmap(DC, ClientRect.Right, ClientRect.Bottom); //创建一个设备兼容位图(内存中) ReleaseDC(0, DC); MemDC := CreateCompatibleDC(0); //创建一个兼容上下文绘图设备(内存中的) OldBitmap := SelectObject(MemDC, MemBitmap); //将位图选中为绘图设备的当前对象,返回值为老的对象,给予保存 try DC := BeginPaint(Handle, PS); //申明开始绘制,该函数会返回当前控件的上下文绘图设备(屏幕上的) Perform(WM_ERASEBKGND, MemDC, MemDC); //发送背景清空消息(内存中的) Message.DC := MemDC; (注★ 内存中的设备,该值不为零,会被上面的代码处理) WMPaint(Message); (递归调用本过程,让前面部分流程代码绘制图像到内存中) Message.DC := 0; BitBlt(DC, 0, 0, ClientRect.Right, ClientRect.Bottom, MemDC, 0, 0, SRCCOPY); (将内存中的图像拷贝到屏幕上) EndPaint(Handle, PS); (结束绘制,并使得当前屏幕的无效区域变为有效)
finally SelectObject(MemDC, OldBitmap); (重新将老的对象选择回去) DeleteDC(MemDC); (删除内存中的上下文设备) DeleteObject(MemBitmap); (删除内存中的对象) end; end; end;
另外 BeginPaint和getdc虽然返回值相同,但他们有明显区别。
BeginPaint和EndPaint常用于wm paint消息,且仅绘制无效区域,并使其有效。
就是说 getdc属于主动型,而 BeginPaint 属于被动型的需在存在无效区域时才工作。
更多细节部分,可参看msdn
|
请发表评论