调用更新过程时,TStatusBar会闪烁。方法来无痛地解决这个问题 [英] TStatusBar flickers when calling Update procedure. Ways to painlessly fix this

查看:121
本文介绍了调用更新过程时,TStatusBar会闪烁。方法来无痛地解决这个问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



重写API调用?我尝试从ComCtrls单元获得更新过程代码,但没有找到...



也许你可以在这里发布一个代码来修复statusbar compoent的闪烁文字改变了吗?我的意思是 - 类似TextUpdate或某种TCanvas方法或PanelsRepaint ...?

闪烁是由以下代码造成的:

 重复
BlockRead(Fp,BuffArrayDebug [LineIndex],DataCapac,TestByteBuff); // DataCapac = SizeOf(DWORD)
ProgressBar1.StepIt;
if RAWFastMode.Checked然后开始//检查快速模式并修改进度条
如果BuffArrayDebug [LineIndex] = 0,则开始ProgressBar2.Max:= FileSize(Fp) - DataCapac; ProgressBar2.Position:=(LineIndex + 1)* DataCapac; LineDecr:= True;结束;
end else begin ProgressBar2.Max:= FileSize(Fp); ProgressBar2.Position:= LineIndex * DataCapac结束;
如果PreviewOpn.Caption ='<'则开始//开始将数据复制到预览区域(如果已扩展)
Memo1.Lines.BeginUpdate;
if(LineIndex mod DataCapac)> 0 HexMerge:= HexMerge + ByteToHex(BuffArrayDebug [LineIndex])else
begin
Memo1.Lines.Add(HexMerge); HexMerge:='';
end;
Memo1.Lines.EndUpdate;
end;
StatusBar1.Panels [0] .Text:='Line:'+格式('%。7d',[LineIndex])+'|数据:'+格式('%。3d',[BuffArrayDebug [LineIndex]])+'| Time:'+ TimeToStr(Time - TimeVarStart); StatusBar1.Update;
如果FindCMDLineSwitch(ParamStr(1))然后开始
TrayIcon.BalloonTitle:='处理'+ ExtractFileName(RAWOpenDialog.FileName)+'并阅读...';
TrayIcon.BalloonHint ='当前行:'+ inttostr(LineIndex)+#10#13 +'Byte Data:'+ inttostr(TestByteBuff)+#10#13 +'Hex Data:'+ ByteToHex(TestByteBuff );
TrayIcon.ShowBalloonHint;
end;
Inc(LineIndex);
直到EOF(Fp);

有什么想法?




有人对此链接发表评论( http.s //www.stevetrefethen / b / b / b / b / b /














$ b $ code> 1类型
2 TMyForm = class(TForm)
3 protected
4过程CreateParams(var Params:TCreateParams);覆盖;
5 end;
6
7 ...
8
9程序TMyForm.CreateParams(var Params:TCreateParams);
10开始
继承11;
12 //如果CheckWin32Version(5,1)然后
14,Params.ExStyle:= Params.ExStyle或WS_EX_COMPOSITED;这只适用于Windows XP及以上
13;
15 end;
16

另外 - 目标不是表单,而是状态栏...如何将此方法分配给状态栏?

我可以给你的最重要的建议是限制状态栏更新的数量大概每秒10到20次。更多只会导致不必要的闪烁,对用户没有任何好处 - 他们无法处理快速的信息。



好吧,如果不行的话:If你想为状态栏使用 WS_EX_COMPOSITED 扩展样式,你基本上有三个选择:
$ b $ ul

  • 创建一个覆盖 CreateParams()方法的后代类,并将其安装到您的IDE中,或者(如果您不想将其作为其创建一个具有相同名称的后代类 TStatusBar $ c>在另一个单元中,重写 CreateParams()方法,并将 ComCtrls 使用状态栏控件。这将创建您自己的 TStatusBar 类的实例,而不是 ComCtrls 中的实例。有关该技术的另一个示例,请参阅此答案,希望它足够清晰。 / p>


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




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

      procedure TForm1.FormCreate(Sender:TObject); 
    var
    SBHandle:HWND;
    begin
    //如果CheckWin32Version(5,1)然后开始
    //这只能在Windows XP和
    之上运行注意:以下调用将创建所有必需的窗口句柄
    SBHandle:= StatusBar1.Handle;
    SetWindowLong(SBHandle,GWL_EXSTYLE,
    GetWindowLong(SBHandle,GWL_EXSTYLE)或WS_EX_COMPOSITED);
    end;
    end;



    修改



    如果您希望自己的代码能够正确支持最新的Windows版本和视觉样式,那么您甚至不应该考虑自己处理 WM_ERASEBKGND - 通常的技术会涉及该方法的空处理程序,并在 WM_PAINT 处理程序中绘制背景。对于像 TStatusBar 这样的标准控件,这并不适用,因为背景必须在某处中绘制。如果您只跳过 WM_ERASEBKGND 处理程序中的背景图,则需要使用跨越所有状态栏的所有者绘制的面板,否则背景根本不会画出来,下面的窗口会闪耀。此外,所有者绘制面板的代码可能会非常复杂。

    再一次,更好的方法是解决发布代码中的混乱问题,正确地将工作人员与显示代码分开,并将状态栏文本的更新速度降低到合理值。在每秒超过显示器更新次数方面,根本没有任何意义,即使这仅适用于游戏和类似的可视化。


    So, here is the discussion I have just read: http://www.mail-archive.com/delphi@delphi.org.nz/msg02315.html

    BeginUpdate and EndUpdate is not thi procedures I need ...

    Overriding API Call? I tried to get Update procedures code from ComCtrls unit, nut did not found...

    Maybe you could post here a code to fix thi flicker of statusbar compoent if the only text changes in it? I mean - something like TextUpdate or some kind of TCanvas method or PanelsRepaint ... ?

    The flickering is caused by this code:

    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);
    

    Any ideas?


    There was comment with this link ( http://www.stevetrefethen.com/blog/UsingTheWSEXCOMPOSITEWindowStyleToEliminateFlickerOnWindowsXP.aspx ) and there is procedure that works ( no flickering whastsoever ), BUT IT IS VVVVVVVEEEEEERRRRRRYYYYYY SLOW!

     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 
    

    Also - the target is not the form, but the StatusBar ... how to assign this method to statusbar?

    解决方案

    The most important advise I can give you is to limit the number of status bar updates to maybe 10 or 20 per seconds. More will just cause unnecessary flicker, without any benefit for the user - they can't process the information that fast anyway.

    OK, with that out of the way: If you want to use the WS_EX_COMPOSITED extended style for the status bar you have basically three options:

    • Create a descendent class that overrides the CreateParams() method and either install this into your IDE or (if you don't want to have it as its own component in the IDE) create the status bar at runtime.

    • Create a descendent class with the same name TStatusBar in another unit, override the CreateParams() method, and add this unit after ComCtrls to the form units using status bar controls. This will create an instance of your own TStatusBar class instead of the one in ComCtrls. See this answer for another example of the technique, hopefully its clear enough.

    • Use the vanilla TStatusBar class and set the WS_EX_COMPOSITED extended style at runtime.

    I prefer the third option as the easiest one to experiment with, so here's the sample code:

    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;
    

    Edit:

    If you want your code to properly support recent Windows versions and visual styles you should not even think of handling WM_ERASEBKGND yourself - the usual technique involves an empty handler for that method, and drawing the background in the WM_PAINT handler. This doesn't really work for standard controls like TStatusBar, as the background has to be drawn somewhere. If you just skip the background drawing in the WM_ERASEBKGND handler you will need to use owner-drawn panels spanning all of the status bar, otherwise the background simply won't be drawn, and the window underneath will shine through. Besides, the code for the owner-drawn panel would probably be very complex.

    Again, a much better course of action would be to untangle the mess in your posted code, properly separate worker from display code, and reduce the update speed of your status bar texts to something reasonable. There just isn't any sense at all in going past the number of monitor updates per second, and even this is sensible only for games and similar visualizations.

    这篇关于调用更新过程时,TStatusBar会闪烁。方法来无痛地解决这个问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆