如何解决在窗体或图像上快速绘制、移动控件时出现的闪烁问题?
VCL窗体/控件绘制闪烁解决方案
触发原因
该闪烁由VCL默认重绘逻辑导致:修改控件位置、触发自定义绘制时,系统默认会先清空对应区域的背景,再绘制新的内容,两个操作的时间差就会表现为肉眼可见的闪烁。
可用修复方案
- 方案1:开启双缓冲
直接在窗体属性面板设置DoubleBuffered为True,或在窗体初始化代码中添加:
双缓冲机制会先在内存中完成所有绘制计算,再一次性输出到屏幕,消除擦除和绘制的时间差。Form1.DoubleBuffered := True; // 涉及到的子控件也可同步开启双缓冲 Image1.DoubleBuffered := True; - 方案2:禁用不必要的背景擦除
重写窗体的WM_ERASEBKGND消息,阻止系统自动擦除背景:type TForm1 = class(TForm) // 原有控件声明省略 private procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND; // 其他私有声明省略 public // 共有声明省略 end; implementation procedure TForm1.WMEraseBkgnd(var Message: TWMEraseBkgnd); begin // 直接返回已处理标记,跳过系统默认擦除背景操作 Message.Result := 1; end; - 方案3:修改控件属性时临时挂起重绘
频繁修改控件位置/外观时,可以先暂停控件重绘,全部修改完成后再一次性刷新:
你提供的Timer移动Image的代码可修改为:procedure TForm1.Timer1Timer(Sender: TObject); begin Image1.Perform(WM_SETREDRAW, WPARAM(False), 0); Image1.Left := Image1.Left + 1; Image1.Perform(WM_SETREDRAW, WPARAM(True), 0); Image1.Invalidate; end; - 方案4:全局开启应用合成缓冲
如果你开发的所有应用都存在该问题,可以直接在工程入口处添加系统级合成缓冲配置,一次性解决所有窗体的闪烁问题:
打开工程的dpr文件,在Application.Initialize后添加以下代码:Application.Initialize; // 添加下面这行 SetWindowLong(Application.Handle, GWL_EXSTYLE, GetWindowLong(Application.Handle, GWL_EXSTYLE) or WS_EX_COMPOSITED); Application.MainFormOnTaskbar := True; Application.CreateForm(TForm1, Form1); Application.Run;
你给出的示例代码使用方案1或方案2即可完全解决Image移动时的闪烁问题。
内容的提问来源于stack exchange,提问作者Codrut
相关产品推荐
相关产品推荐

