TStatusBar调用Update过程时闪烁。 方法无痛解决这个问题(TStatusBar f

2019-09-19 06:42发布

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

的BeginUpdate和EndUpdate不是我需要THI程序...

压倒一切的API调用? 我试图让从ComCtrls单元更新程序代码,螺母没有发现...

也许你可以在这里发表一个代码来解决状态栏compoent的THI闪烁如果只有文字在有变化? 我的意思是 - 像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 ),而且是工作(无闪烁whastsoever)的过程,但它是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 

此外 - 目标不是形式,而是在状态栏...如何分配这个方法状态栏?

Answer 1:

我可以给你最重要的建议是状态栏更新的次数限制为也许10或20每秒。 更多只会造成不必要的闪烁,无需用户任何好处 - 他们无法反正处理信息快。

OK,有了这样的方式:如果你想使用WS_EX_COMPOSITED扩展样式你有三个基本选择状态栏:

  • 创建一个派生类,覆盖CreateParams()方法,要么这个安装到你的IDE(如果你不想把它作为IDE它自己的组件)在运行时创建的状态栏。

  • 创建具有相同名称的子孙类TStatusBar在另一个单元中,覆盖CreateParams()方法,和之后添加此单元ComCtrls使用状态条控件的形式的单元。 这将创建自己的实例TStatusBar类,而不是一个在ComCtrls 。 见这个答案对于该技术的另一个例子,希望它的清楚。

  • 使用香草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 ,作为背景在某处被绘制。 如果你只是跳过背景的绘制WM_ERASEBKGND处理程序,你将需要使用自绘板跨越所有的状态栏 ,否则单纯的背景将不会被绘制,而窗口下方将彪炳。 此外,为业主绘制面板的代码很可能是非常复杂的。

此外,行动更好的办法是理清在您发布的代码的混乱,从显示的代码正确单独的工作,并降低你的状态栏文本的更新速度的东西合理。 那里只是没有任何意义在过去去每秒钟显示器的更新次数可言,甚至这只是为游戏和类似的可视化明智的。



Answer 2:

您应该检查是否TWinControl.DoubleBuffered属性设置为True TStatusBar组件将使其发挥作用。 你也可以尝试启用此属性状态栏的父组件(可能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 ;

它为我工作。 祝好运!



文章来源: TStatusBar flickers when calling Update procedure. Ways to painlessly fix this