views:

402

answers:

2

So, here is the discussion I have just read: http://www.mail-archive.com/[email protected]/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?

+1  A: 

You should check whether setting the TWinControl.DoubleBuffered property to True of the TStatusBar component will make it work. Also you can try enabling this property to the status bar's parent component (probably TForm). It's a blind shot - don't have access to the compiler from here. Another thought is to override the *WM_ERASEBKGND* message without calling inherited. First example found after using google: here.

----- Update after author's comment

I finally got access to the compiler and now it's working. We can use the WS_EX_COMPOSITED solution. All you need is is to create your own custom component basing on TCustomStatusBar or just create a class wrapper and create your status bar instance in runtime. Like this:

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 ;

And it works for me. Good luck!

Darius
Well, I did take a look at this link and as I knew, there is doublebuffered property, which did not help me ....Also - Question is updated. Please give some other answers / comments!
HX_unbanned
+1  A: 

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.

mghie
Maybe you should do as mghie suggested: limit the frequency of StatusBar's updates - just call update every n-th time.
Darius
@Darius - well, take a look at first post - blockread() reads binary file, even with optinal check parameter, very fast and this frequency is important as this statusbar model can be used as instant debugger.
HX_unbanned
fix spelling with OR statement, mghie ;) Also - there is now some system lag when used this procedure - as warned in my link :( Hm, any other solution? Mybe it could be done, of course, with a bit larger code, but with WM_ERASEBKGND ... althought I did search ComCtrl unit, but did not find full StatusBar.Update code ... As much as I understand, the overriding of this API call would be simply not calling it in practice?
HX_unbanned
In my opinion limiting the frequency of StatusBar updates won't make those data less informational. In fact, such updates shouldn't be called that way, cause those VCL calls are affecting the performance of whole I/O operation. Much better approach would be using a separate thread for doing this.
Darius
hm, than I could use Shell_Notify() or SHChangeNotify() ? Problem is that I dont know correct API Call syntax to do it ...And - I never read about ShelObj and ShellAPI units in depth ...
HX_unbanned
@mghie - about Edit - emm, yeah, my goul is to make full ( although pretty curvehands.dll-like ) support for WinXP SP3 and Post-Windows XP versions, so I mainly try to go through Shell resources, not deal with GDI, TCanvas, and Graphics classes/units ...
HX_unbanned
@HX_unbanned: Sorry, I don't understand what Shell programming has to do with this, at all.
mghie
@mghie - Ok, never mind then. I suppose I am thinking the wrong way after all. Don't get confused - I'm just learning delphi.imho all vcl components connect during runetime directly to os shell and takes from them all the resources. the os api then manages shells resources, so i think that they are pretty dependent. Maybe I am wrong? If yes, please give some links to read and learn. P.S. Sorry if I disinform you and other members and readers. We all are just humans..
HX_unbanned