簡體   English   中英

調用更新過程時,TStatusBar閃爍。 輕松解決此問題的方法

[英]TStatusBar flickers when calling Update procedure. Ways to painlessly fix this

因此,這是我剛剛閱讀的討論: http : //www.mail-archive.com/delphi@delphi.org.nz/msg02315.html

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

重寫API調用? 我試圖從ComCtrls單元獲取更新過程代碼,但未找到螺母。

也許您可以在此處發布代碼以解決狀態欄組件閃爍的問題,如果其中僅有文本更改? 我的意思是-類似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 ),並且該程序有效(無閃爍),但VVVVVVVVEEEEEERRRRRRYYYYYY慢!

 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 

另外-目標不是表單,而是StatusBar ...如何將此方法分配給statusbar?

您應該檢查是否將TStatusBar組件的TWinControl.DoubleBuffered屬性設置為True可以使它工作。 您也可以嘗試對狀態欄的父組件(可能是TForm)啟用此屬性。 這是一個盲目的鏡頭-無法從此處訪問編譯器。 另一種認為是覆蓋WM_ERASEBKGND消息,而不調用繼承 使用google后找到的第一個示例: 此處

-----作者評論后更新

我終於可以訪問編譯器,並且現在可以正常工作了。 我們可以使用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 ;

它對我有用。 祝好運!

我能給您的最重要的建議是將狀態欄更新的數量限制為每秒10或20。 更多信息只會導致不必要的閃爍,對用戶沒有任何好處-他們仍然無法快速處理信息。

好的,順便說一句:如果要對狀態欄使用WS_EX_COMPOSITED擴展樣式,則基本上有三個選擇:

  • 創建一個重寫CreateParams()方法的后代類,然后將其安裝到您的IDE中,或者(如果您不想在IDE中將其作為自己的組件)在運行時創建狀態欄。

  • 在另一個單元中創建一個具有相同名稱TStatusBar的后代類,重寫CreateParams()方法,然后使用狀態欄控件將此ComCtrls之后的單元添加到表單單元。 這將創建您自己的TStatusBar類的實例,而不是ComCtrls中的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這樣的標准控件來說TStatusBar ,因為背景必須繪制在某處 如果僅跳過WM_ERASEBKGND處理程序中的背景圖,則將需要使用跨所有狀態欄的所有者繪制的面板,否則背景將不會被繪制,並且下面的窗口將通過。 此外,所有者繪制面板的代碼可能非常復雜。

同樣,更好的做法是解開已發布代碼中的混亂情況,將工作人員與顯示代碼正確分開,並將狀態欄文本的更新速度降低到合理的水平。 超過每秒監視器更新的數量根本沒有任何意義,即使只有游戲和類似的可視化程序也才有意義。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM