Quick Tip #2: Fixing flicker caused by WM_ERASEBKGND in a Delphi VCL app

In Delphi’s VCL framework there is a property on TWinControl called DoubleBuffered which can help reduce or eliminate window flicker. To see a simple example of it’s effectiveness try the following:

  1. Create a new VCL application
  2. Drop a TMemo control
  3. Set Align on Memo1 to alClient
  4. Using the Lines property add some text to the memo
  5. Run the application and resize the form

Notice how the text in the control flickers. Now add an OnCreate event to Form1 and put the following code:

Memo1.DoubleBuffered := True;

Run the application again and resize the form. Notice that the flicker is gone. In a future release we’ll publish the DoubleBuffered property to allow you to set it directly from the Object Inspector but until then writing a little code is necessary.

You might be wondering why isn’t DoubleBuffered set to true by default? The reason is performance though the average PC’s processing power has significantly increased since we added this feature to the VCL. A machine that’s capable of running Windows Vista with the Areo Glass UI will easily be able to handle DoubleBuffering.

Finally, let’s to the reason I wrote this post which is handling WM_ERASEBKGND. If you’ve written your own components that handle their own painting you should consider the affect of DoubleBuffering in your message handling code. An example is in the default implementation of TWinControl’s WMERASEBKGND method which contains the following:

{ Only erase background if we're not doublebuffering or painting to memory. } if not FDoubleBuffered or (TMessage(Message).wParam = TMessage(Message).lParam) then FillRect(Message.DC, ClientRect, FBrush.Handle);

Consider doing something similar in your code to support DoubleBuffering. I have been working on reducing flicker within the Delphi IDE itself and there were a few WM_ERASEBKGND handlers which were not written with DoubleBuffering in mind (but that’s fixed now). We’re not quite down to a flick-free IDE but it’s getting very close.

[UPDATE Feb 1]: Fix the property name in the first sentence, it’s “DoubleBuffered” not “DoubleBuffering”
[UPDATE May, 2008] Related posts:

Quick Tip: FullRepaint and fixing flicker in a Delphi VCL app
Using the WS_EX_COMPOSITE window style to eliminate flicker on Windows XP

12 thoughts on “Quick Tip #2: Fixing flicker caused by WM_ERASEBKGND in a Delphi VCL app

  1. Thanks for the tip. I’ve created this little procedure to set some of these preferences. Simply call ReplicatePreferences from the OnCreate event of a form and set the initial parameter to form e.g. ReplicatePreferences(MainForm). Maybe someone else will find it useful. Steve
    procedure TMainForm.ReplicatePreferences(c: TComponent);
    var
    i : integer;
    begin
    if (c is TWinControl) then
    TWinControl(c).DoubleBuffered := true;
    if (c is TPanel) then
    TPanel(c).FullRepaint := false;
    if c.ComponentCount > 0 then
    begin
    for i := c.ComponentCount – 1 downto 0 do
    ReplicatePreferences(c.Components[i]);
    end;
    end;

  2. Awesome info.
    I do a lot of graphics programming and although I knew about the DoubleBuffered property I wasn’t aware of the WM_ERASEBKGND considerations.
    Thanks!

  3. Nice.
    If you set DoubleBuffered on a TRichEdit, it will stop paiting though. Not nice.
    Will you also fix the flicker of TPageControls?
    The tab pages flicker like crazy when you resize the form.

  4. I’m already working on a complete rewrite of the FlickerReduce unit. And at the moment I have only two issues left (TScrollbox containing a TPanel containing a TGroupbox, and TRadioButton). And my technique doesn’t use double buffering.
    BTW: The PageControl flicker because the TPageControl erases its complete ClientRect, including the Tabsheet with the Brush.Color. Using ExcludeClipRect(ActiveTabSheet.BoundsRect) in the TPageControl.WM_ERASEBKGND handler removes the flicker.

  5. Hi Tjipke,
    No sooner had I posted that, that I thought the same thing. The Vista window manager is now essentially double buffering anyway though there are still uses for double buffering as we’ve found working with the Glass UI. Thanks for the link!

  6. Andreas,
    I’ve been investigating the issues with the page control and it certainly has many problems when it comes to double buffering. It not only suffers from the problem mentioned in this post TTabSheet has several problems as well including:
    – not setting DoubleBuffered when TPageControl.DoubleBuffered is set
    – not overriding WM_ERASEBKGND and handling client area painting correctly when DoubleBuffered is true
    FWIW, I’ve fixed these problems in our R&D build but I’d be interested to see what you did as well. I tried your suggestion above but didn’t see the desired improvements.

  7. I set the double buffered property to True in form create event….but still i get flickering of the controls………..
    Can any body suggest , to avoid the flickering……..
    Note: Mainly the form has scollbox and inside the scrollbox i have dynamically building the controls

Comments are closed.