Use BeginUpdate and EndUpdate to increase performance of Delphi Visual / Design Components

Use BeginUpdate and EndUpdate to increase performance of Delphi Visual / Design Components

If you are using Delphi visual / design components like a ListBox, Memo, TreeList, ListView, DataView etc. and you add or modify a lot of items (lines, nodes etc.), the component's performance becomes very slow. This is due to the fact that after each change, it is redrawn on the screen.

Thus, modifying 10000 items of a ListBox causes 10000 redraws, and that takes from several seconds to several minutes, depending on the computer's speed and the complexity of the process. Imagine how slow it can become if the process involves inserting, deleting, modifying and swapping many thousands of items. But you can speed up things enormously with the following tip:

Call BeginUpdate before making the changes to the items. When all changes are complete, call EndUpdate to show the changes on screen. BeginUpdate and EndUpdate prevent excessive redraws and speed up processing time when items are added, deleted, or inserted.

Using BeginUpdate and EndUpdate is an implementation of the lock and unlock pattern in Delphi. It allows you to you temporarily lock an aspect of the class, avoiding unneeded notifications.

Here's a simple source code example for using this technique with a ListBox:

ListBox1.Items.BeginUpdate;

for i := 1 to 10000 do
    ListBox1.Items.Add('abcd');

ListBox1.Items.EndUpdate;

To give you an idea of the improvement, we timed the code above (your PC may be faster or slower):

without the BeginUpdate/EndUpdate lines: 4.3 seconds...
with BeginUpdate/EndUpdate: 0.1 seconds, that's 43 times faster!

Here's a source code example for using this technique with a Memo:

Memo1.Lines.BeginUpdate;

for i := 1 to 5000 do
    Memo1.Lines.Add('abcd');

Memo1.Lines.EndUpdate;

without BeginUpdate/EndUpdate: 25 seconds...
with BeginUpdate/EndUpdate: 0.6 seconds!

Example with Panels

The following example adds a panel to the status bar control when the user clicks the button and adds a caption to the panel. The code uses BeginUpdate and EndUpdate to prevent repaints until the operation is complete. A try...finally block ensures that EndUpdate is called even when an exception occurs.

procedure TForm1.Button1Click(Sender: TObject);
var
  PanelIndex : Integer;
begin
  with StatusBar1 do
  begin
    Panels.BeginUpdate;
    PanelIndex := StatusBar1.Panels.Count - 1;
    try
      Panels.Add;
      Inc(PanelIndex);
      Panels.Items[PanelIndex].Text := 
        'Panel' + IntToStr(PanelIndex);
    finally
      Panels.EndUpdate;
    end;
  end;
end;