======================================================
注:本文源代码点此下载
======================================================
有时,在有大量图片或者复杂的界面下,会出现界面闪烁。这是由于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
======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/