ALZ*_*ALZ 9 delphi winapi gdi flicker delphi-7
我在表单上有一些自定义进度条,每秒更新/刷新两次,它们闪烁.
TMyProgressBar = class(TCustomControl)
Run Code Online (Sandbox Code Playgroud)
我继承了控件TCustomControl,因为我需要Handle和一些TWinControl事件.控件(最多64个项目)是动态创建的,并放在ScrollBox上.当进度更新时,我先打电话InvalidateRect.
所有的绘画工作(一组矩形,DrawText等等 - 从这里启发)都在存储器DC中执行,然后BitBlt在控制器的DC上执行.它无论如何都在闪烁,似乎组件消失并重新出现.恕我直言,它是由背景擦除引起的.
在这个无闪烁的绘图建议中,它是WM_ERASEBKGND按以下方式编写的:
type
TMyProgressBar = class(TCustomControl)
procedure WMEraseBkGnd(var Message:TMessage); message WM_ERASEBKGND;
procedure TMyProgressBar.WMEraseBkGnd(var Message: TMessage);
begin
Message.Result := 1;
end;
Run Code Online (Sandbox Code Playgroud)
但是在另一个组件中,通过TMS(TAdvProgressBar),Result设置0为相同的消息.
现在Windows文档说明:
如果应用程序删除背景,则应返回非零值; 否则,它应该返回零.
我测试了两种变体(结果= 0,1),令我惊讶的是都避免了闪烁.
那么现在,我需要在Delphi代码中加入什么?什么是正确的方法?
没关系.重要的是,只要你不打电话inherited,默认窗口程序就不会删除背景.由于您正在绘制控件的整个表面,因此不需要默认处理.
返回"0"或"1"(非"0")时的更改是,在BeginPaint调用时,系统会相应地设置fErase成员PAINTSTRUCT.返回"0"时,它设置为"True",表示必须在绘制过程中擦除背景.对于'1',它设置为'False',表示不需要擦除.BeginPaint被称为TWinControl.PaintHandler.没有人检查过什么fErase,VCL只使用设备上下文BeginPaint返回,所以你返回的内容没有任何区别.
尽管如此,我还是会回归'1',从概念上暗示已经完成了擦除工作.