调用更新过程时,TStatusBar会闪烁。 方法来无痛地解决这个问题

所以,这里是我刚刚阅读的讨论: http : //www.mail-archive.com/delphi@delphi.org.nz/msg02315.html

BeginUpdate和EndUpdate不是我需要的程序…

重写API调用? 我试图从ComCtrls单位得到更新程序代码,坚果没有find…

也许你可以在这里发布一个代码来修复状态栏compoent的闪烁,如果唯一的文本改变了吗? 我的意思是 – 像TextUpdate或某种TCanvas方法或PanelsRepaint …?

闪烁是由以下代码引起的:

Repeat BlockRead(Fp, BuffArrayDebug[LineIndex], DataCapac, TestByteBuff); // DataCapac = SizeOf(DWORD) ProgressBar1.StepIt; if RAWFastMode.Checked then begin // checks for fast mode and modifyies progressbar if BuffArrayDebug[LineIndex] = 0 then begin ProgressBar2.Max := FileSize(Fp) - DataCapac; ProgressBar2.Position := (LineIndex + 1) * DataCapac; LineDecr := True; end; end else begin ProgressBar2.Max := FileSize(Fp); ProgressBar2.Position := LineIndex * DataCapac end; if PreviewOpn.Caption = '<' then begin // starts data copying to preview area if expanded Memo1.Lines.BeginUpdate; if (LineIndex mod DataCapac) > 0 then HexMerge := HexMerge + ByteToHex(BuffArrayDebug[LineIndex]) else begin Memo1.Lines.Add(HexMerge); HexMerge := ''; end; Memo1.Lines.EndUpdate; end; StatusBar1.Panels[0].Text := 'Line: ' + Format('%.7d',[LineIndex]) + ' | Data: ' + Format('%.3d',[BuffArrayDebug[LineIndex]]) + ' | Time: ' + TimeToStr(Time - TimeVarStart); StatusBar1.Update; if FindCMDLineSwitch(ParamStr(1)) then begin TrayIcon.BalloonTitle := 'Processing ' + ExtractFileName(RAWOpenDialog.FileName) + ' and reading ...'; TrayIcon.BalloonHint := 'Current Line: ' + inttostr(LineIndex) + #10#13 + ' Byte Data: ' + inttostr(TestByteBuff) + #10#13 + ' Hex Data: ' + ByteToHex(TestByteBuff); TrayIcon.ShowBalloonHint; end; Inc(LineIndex); Until EOF(Fp); 

有任何想法吗?


有这个链接的评论( http://www.stevetrefethen.com/blog/UsingTheWSEXCOMPOSITEWindowStyleToEliminateFlickerOnWindowsXP.aspx ),并有程序工作(无闪烁),但它是VVVVVVVEEEEEERRRRRRYYYYYY慢!

  1 type 2 TMyForm = class(TForm) 3 protected 4 procedure CreateParams(var Params: TCreateParams); override; 5 end; 6 7 ... 8 9 procedure TMyForm.CreateParams(var Params: TCreateParams); 10 begin 11 inherited; 12 // This only works on Windows XP and above 13 if CheckWin32Version(5, 1) then 14 Params.ExStyle := Params.ExStyle or WS_EX_COMPOSITED; 15 end; 16 

此外 – 目标不是forms,但StatusBar …如何将此方法分配给状态栏?

Solutions Collecting From Web of "调用更新过程时,TStatusBar会闪烁。 方法来无痛地解决这个问题"

我可以给你的最重要的建议是限制状态栏更新的数量可能每秒10或20。 更多只会造成不必要的闪烁,对用户没有任何好处 – 它们无法处理快速的信息。

好,就这样:如果你想使用状态栏的WS_EX_COMPOSITED扩展风格,你基本上有三个选择:

  • 创建一个覆盖CreateParams()方法的后代类,并将其安装到您的IDE中,或者(如果您不想将其作为IDE中的组件)在运行时创建状态栏。

  • 在另一个单元中创建一个具有相同名称TStatusBar的后代类,重写CreateParams()方法,并在ComCtrls之后将该单元添加到使用状态栏控件的表单元。 这将创建您自己的TStatusBar类的实例,而不是TStatusBar中的一个。 看到这个答案的另一个例子,希望它足够清楚。

  • 使用vanilla TStatusBar类并在运行时设置WS_EX_COMPOSITED扩展样式。

我更喜欢第三个选项作为最简单的实验,所以这里是示例代码:

 procedure TForm1.FormCreate(Sender: TObject); var SBHandle: HWND; begin // This only works on Windows XP and above if CheckWin32Version(5, 1) then begin // NOTE: the following call will create all necessary window handles SBHandle := StatusBar1.Handle; SetWindowLong(SBHandle, GWL_EXSTYLE, GetWindowLong(SBHandle, GWL_EXSTYLE) or WS_EX_COMPOSITED); end; end; 

编辑:

如果你想让你的代码正确地支持最近的Windows版本和视觉样式,你甚至不应该想到自己处理WM_ERASEBKGND – 通常的技术是使用该方法的空处理程序,并在WM_PAINT处理程序中绘制背景。 这对于像TStatusBar这样的标准控件TStatusBar ,因为背景必须绘制在某个地方 。 如果只是跳过WM_ERASEBKGND处理程序中的背景图,则需要使用横跨所有状态栏的所有者绘制的面板,否则不会绘制背景,并且下面的窗口会发光。 此外,所有者绘制面板的代码可能会非常复杂。

再一次,一个更好的行动将是解决你的发布代码中的混乱,正确地分开工人和显示代码,并降低你的状态栏文本的更新速度合理。 在每秒超过显示器更新次数的情况下,根本没有任何意义,甚至只有游戏和类似的可视化才是明智的。

您应该检查是否将TStatusBar组件的TWinControl.DoubleBuffered属性设置为True将使其工作。 您也可以尝试启用此属性到状态栏的父组件(可能TForm)。 这是一个盲目的 – 从这里没有访问编译器。 另一个想法是重写WM_ERASEBKGND消息而不调用继承 。 使用谷歌之后发现的第一个例子: 这里 。

—–作者评论后更新

我终于可以访问编译器,现在它正在工作。 我们可以使用WS_EX_COMPOSITED解决方案。 所有你需要的是基于TCustomStatusBar创建你自己的自定义组件,或者只是创建一个类包装,并在运行时创建你的状态栏实例。 喜欢这个:

 TMyStatusBar = class( TCustomStatusBar ) protected { Flickering work-around } procedure CreateParams( var Params : TCreateParams ) ; override ; end ; TForm1 = class( TForm ) // (...) private FStatusBar : TMyStatusBar ; // (...) end ; ------------- procedure TMyStatusBar.CreateParams( var Params : TCreateParams ) ; begin inherited ; if CheckWin32Version( 5,1 ) then Params.ExStyle := Params.ExStyle or WS_EX_COMPOSITED ; end ; ------------- { Creating component in runtime } procedure TForm1.FormCreate( Sender : TObject ) ; begin FStatusBar := TMyStatusBar.Create( Self ) ; FStatusBar.Parent := Self ; FStatusBar.Panels.Add ; end ; 

它适用于我。 祝你好运!