Nobody has the solution that solves the speed problem. But lets take a tour of the various answers that speed it up somewhat (although nowhere near fast enough to consider the problem solved).
Our test will be of adding 250 items.
Test 1 - Add to raw TStrings - 120,000 items/sec
First we'll add 250 items to a TStringList. Without any other overhead or cost we will be how have it can happen.
var
i: Integer;
sl: TStrings;
begin
sl := TStringList.Create;
sl.BeginUpdate;
for i := 1 to 250 do
sl.Items.Add('Test');
sl.EndUpdate;
end;
That adds 250 items in 0.0081 ms (120,000 items/sec) on my 3.5 GHz i7-2700.
This is the fastest we could ever reasonably expect.
Test 2 - Adding to TComboBox.Items TStrings - 8 items/sec (99.993% slower)
Now our test function will actually add things to a TComboBox.Items.
var
i: Integer;
begin
for i := 1 to 250 do
AComboBox.Items.Add('Test');
end;
That adds 250 items in 124.9 ms (8.00 items/sec).
Test 3 - Turn off Redraw - 24 items/sec (99.98% slower)
Next we turn off drawing of the control by calling WM_SETREDRAW
var
i: Integer;
begin
AComboBox.Perform(WM_SETREDRAW, 0, 0); // turn OFF redraw
for i := 1 to 250 do
AComboBox.Items.Add('Test');
AComboBox.Perform(WM_SETREDRAW, 1, 0); // turn ON redraw
end;
That adds 250 items in 41.3397 ms (24.2 items/sec).
Test 4 - Items.BeginUpdate - 24 items/sec (99.98% slower)
You should note that the TCustomComboBoxStrings class (which is the TStrings descendant used internally by the TComboBox already calls WM_SETREDRAW
for you when you call BeginUpdate / EndUpdate:
procedure TCustomComboBoxStrings.SetUpdateState(Updating: Boolean);
begin
SendMessage(ComboBox.Handle, WM_SETREDRAW, Ord(not Updating), 0);
if not Updating then ComboBox.Refresh;
end;
So that means that you can dispense with the call to WM_SETREDRAW
and just use the canonical Delphi pattern:
var
i: Integer;
begin
AComboBox.Items.BeginUpdate; // turn OFF redraw
for i := 1 to 250 do
AComboBox.Items.Add('Test');
AComboBox.Items.EndUpdate; // turn ON redraw
end;
That adds 250 items in 42.1127 ms (23.74 items/sec). The extra overhead of calling the TStrings.BeginUpdate wrapper is negligible.
Test 5 - CB_INITSTORAGE - 24 items/sec (99.98% slower)
Then we come to the mytical CB_INITSTORAGE
method. The intention is that you tell the ComboBox how many items you are about to add, and how much memory (in bytes) it is expected to take. This lets the Combobox preallocate memory once.
var
i: Integer;
begin
AComboBox.Perform(CB_INITSTORAGE, 250, 250*6*2); // 12 bytes for "Test\r\n"
AComboBox.Items.BeginUpdate; // turn OFF redraw
for i := 1 to 250 do
AComboBox.Items.Add('Test');
AComboBox.Items.EndUpdate; // turn ON redraw
end;
That adds 250 items in 41.8486 ms (23.9 items/sec).
Which means it adds no improvement whatsoever. In fact i could not get CB_INITSTORAGE
to give any improvmenet anywhere along the line. Perhaps the COMBOBOX control of Windows XP in 2004 benefitted from pre-allocating memory. But it seems that the control has internally solved the problem of repeated incremental memory allocations, and now allocates memory in chunks, and the usefulness of CB_INITSTORAGE
no longer exists.
Summary
Test |
Time to add 250 items (ms) |
Speed (items/sec) |
Add to ComboBox |
124.9 ms |
8 |
Set Redraw |
41.3397 ms |
24.2 |
BeginUpdate |
42.1127 ms |
23.8 |
Init Storage |
41.8486 ms |
23.9 |
Raw TStringList |
0.0081 ms |
120000 |

Using the methods described above, you boost your performance:
- Before:
99.9933% slower than it should be
- After:
99.9809% slower than it should be
For a dramatic 0.01% speedup!
Bonus Chatter
Some people might suggest calling .AddStrings
(or .AddObjects
as your case may be):
begin
AComboBox.Items.AddStrings(SourceList);
end;
What they dont' relize is that AddStrings is identical to Case 4 above:
procedure TStrings.AddStrings(Strings: TStrings);
var
I: Integer;
begin
BeginUpdate;
try
for I := 0 to Strings.Count - 1 do
AddObject(Strings[I], Strings.Objects[I]);
finally
EndUpdate;
end;
end;
So we not speak of AddStrings (or AddObjects) anymore, as they are not relevant to our discussion.
Bonus Reading