Why does TStringList have BeginUpdate and EndUpdate?
Asked Answered
I

3

15

I understand that using BeginUpdate and EndUpdate on VCL controls such as TListBox speeds up the process of populating the control with Items as it prevents the control from being repainted, until EndUpdate is called.

Example:

procedure TForm1.AddItems;
var
  i: Integer;
begin
  Screen.Cursor := crHourGlass;
  try
    for i := 0 to 5000 do
    begin
      ListBox1.Items.Add('Item' + IntToStr(i));
    end;
  finally
    Screen.Cursor := crDefault;
  end;
end;

The above will have a delay because the Listbox is allowed to be repainted, but the delay can be shorted by preventing repainting like so:

procedure TForm1.AddItems;
var
  i: Integer;
begin
  Screen.Cursor := crHourGlass;
  try
    ListBox1.Items.BeginUpdate;
    try
      for i := 0 to 5000 do
      begin
        ListBox1.Items.Add('Item' + IntToStr(i));
      end;
    finally
      ListBox1.Items.EndUpdate;
    end;
  finally
    Screen.Cursor := crDefault;
  end;
end;

Now I tested this using a TStringList:

procedure TForm1.AddItems;
var
  SL: TStringList;
  i: Integer;
begin
  SL := TStringList.Create;
  try
    Screen.Cursor := crHourGlass;
    try
      SL.BeginUpdate;
      try
        for i := 0 to 5000 do
        begin
          SL.Add('Item' + IntToStr(i));
        end;
      finally
        SL.EndUpdate;
      end;

      ListBox1.Items.Assign(SL);
    finally
      Screen.Cursor := crDefault;
    end;
  finally
    SL.Free;
  end;
end;

It seems that regardless if the TStringList uses BegindUpdate and EndUpdate, the list is populated at approximately the same speed..

Are they really needed though as the TStringList is performed in memory and not visually. Should I use BeginUpdate and EndUpdate on a TStringList anyway, is it good practice to do this?

I feel silly for asking this but why does the TStringList have the procedures BeginUpdate and EndUpdate?

I think I may have answered my own question here, either way I would like to hear your views.

Thanks :)

Isomerism answered 5/2, 2012 at 16:24 Comment(0)
M
24

The BeginUpdate inhibits the OnChanging and OnChange events of the stringlist. Depending on what is connected, it can speed up things significantly.

In your example the BeginUpdate/EndUpdate doesn't make much difference. Using a TStringlist instance and assigning it to the listview is quite a valid approach.

Memoirs answered 5/2, 2012 at 16:28 Comment(1)
@RRUZ, indeed! Thanks for the hint.Memoirs
P
10

BeginUpdate and EndUpdate are introduced in the abstract base class TStrings. So TStringList inherits this capability even though it's not particularly useful. However, it is of course useful for many other TStrings descendants.

Remember that many other TStrings descendants have private implementation. For example, the TStrings object associated with a TListBox is private to the implementation section of the StdCtrls unit. The TListBox control exposes item list as TStrings and so to make BeginUpdate and EndUpdate available, they need to be declared in the abstract base class.

In my view you can safely ignore these methods when working with an object that you know to be TStringList.

Now, regarding the code that populates the list view, I see no point whatsoever in using an intermediate TStringList. I would simply populate the list view directly and make use of BeginUpdate/EndUpdate on the list view Items. If you still have performance problems with your list view then the solution is a virtual list view.

Proline answered 5/2, 2012 at 16:35 Comment(5)
+1, The direct use of TListBox.Items.Add might indeed be slightly faster, as TListBox.Items.Assign calls TStrings.AddObject for each entry, which internally calls Add and PutObject.Memoirs
@Uwe That's going to be completely insignificant in comparison to sending the data to the common control. That's going to be the bottleneck. Once you have done BeginUpdate on the list view's Items then all variants will take the same time.Proline
But TListBoxStrings.PutObject calls ListBox.SetItemData which is also implemented with a SendMessage. So it is one SendMessage per item compared to two SendMessages per item.Memoirs
I see, so BeginUpdate and EndUpdate are there because it inherits from parent class TStrings - which ironically I just found out by Ctrl + Clicking on SL.BeginUpdate. Classes.pas shows procedure TStrings.BeginUpdate where TStringList inherits from. I wondered why the StringList had that with it been a non visual control.Isomerism
As Uwe says, it is used in TStringList to modify the behavior of the change notification events, but I think the principal reason it is there is to empower the abstract base class TStrings.Proline
R
2

It's just an implementation of the lock pattern as explained here.

It allows you to you temporarily lock an aspect of the class, avoiding unneeded notifications.

Quite the same as you can find in DB.TDataSet.DisableControls and DB.TDataSet.EnableControls.

Route answered 6/2, 2012 at 10:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.