AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Code-Bibliothek Neuen Beitrag zur Code-Library hinzufügen Delphi Performanceprobleme beim Befüllen von TComboBoxen
Thema durchsuchen
Ansicht
Themen-Optionen

Performanceprobleme beim Befüllen von TComboBoxen

Ein Thema von m.pritscher · begonnen am 24. Jul 2025 · letzter Beitrag vom 31. Jul 2025
Antwort Antwort
m.pritscher

Registriert seit: 24. Jul 2025
6 Beiträge
 
Delphi 10 Seattle Professional
 
#1

Performanceprobleme beim Befüllen von TComboBoxen

  Alt 24. Jul 2025, 14:17
Hallo zusammen,

wir beobachten in unserer Anwendung derzeit sehr lange Ladezeiten – insbesondere beim Befüllen von TComboBox-Elementen.
Das reine Hinzufügen von Strings dauert pro TComboBox etwa 0,5 Sekunden, was sich bei vielen Elementen massiv auf die Gesamtperformance auswirkt.

Zum Vergleich:
In einem separaten Testprogramm mit nahezu identischem Code (ebenfalls TComboBoxen, gleiche Datenbasis)
erfolgt das Befüllen deutlich schneller – nahezu ohne spürbare Verzögerung.

Zusätzlich fällt auf, dass auch einfache Operationen wie "ItemIndex := -1" auf diese TComboBoxen
ebenfalls mehrere hundert Millisekunden (ca. 400–500 ms) benötigen.

Hat jemand eine Idee, woran diese extrem langen Ladezeiten liegen könnten?
Oder warum das Verhalten in der echten Anwendung so stark von einem einfachen Testprogramm abweicht?

Vielen Dank vorab für eure Hilfe!


Delphi-Quellcode:
// ------------------------- Hauptsoftware ------------------------- //
procedure TFenster_EinstInterfaces2.FormCreate(Sender: TObject);
begin
  LogProcedureStart('--- FormCreate ---');
  StartTime := Now;

  // Liste vorbereiten
  varList := TStringList.Create;
  LogTime('Create varList', StartTime);
  StartTime := Now;
  try
    for i := 1 to 500 do
      varList.Add('<Var ' + IntToStr(i) + '>');
    LogTime('Filled varList with 500 entries', StartTime);
    StartTime := Now;

    // Comboboxen-Array
    cmbArray[1] := cmb1; cmbArray[2] := cmb2;
    cmbArray[3] := cmb3; cmbArray[4] := cmb4;
    cmbArray[5] := cmb5; cmbArray[6] := cmb6;
    cmbArray[7] := cmb7; cmbArray[8] := cmb8;
    cmbArray[9] := cmb9; cmbArray[10] := cmb10;

    // Comboboxen befüllen mit Update-Block
    for i := 1 to 10 do
    begin
      cmbArray[i].Items.Assign(varList);
      LogTime('Assigned cmb' + IntToStr(i), StartTime);
      StartTime:= Now;
    end;

  finally
    varList.Free;
    LogTime('Freed varList', StartTime);
    StartTime := Now;
  end;

  LogProcedureEnd('--- FormCreate ---');
end; {FormCreate}


procedure TFenster_EinstInterfaces2.ClearParVarPanel;
begin
  LogProcedureStart('--- ClearParVarPanel ---');

  StepStartTime := Now;
  for i := 1 to 15 do
  begin
    LoopStartTime := Now;
    hcombo := TComboBox(FindComponent('cmb' + IntToStr(i)));
    LogTime('FindComponent für cmb' + IntToStr(i), LoopStartTime);

    if hcombo <> nil then
    begin
      LoopStartTime := Now;
      hcombo.Items.BeginUpdate;
      try
        hcombo.ItemIndex := -1;
      finally
        hcombo.Items.EndUpdate;
      end;
    end
    else
    begin
      LogTime('cmb' + IntToStr(i) + ' = nil', LoopStartTime);
    end;
  end;
  LogTime('cmb-Schleife abgeschlossen', StepStartTime);

  LogProcedureEnd('--- ClearParVarPanel ---');
end; {ClearParVarPanel}
Delphi-Quellcode:
// ------------------------- Testprogramm ------------------------- //
procedure TForm1.FormCreate(Sender: TObject);
var
  VarList: TStringList;
  i, aos: Integer;
  StartStepTime: TDateTime;
  cmbArray: array[1..10] of TComboBox;
begin
  FProcedureStartTime := Now;

  // Anzahl an Strings festlegen
  aos:= 500;

  LogProcedureStart('--- FormCreat ---');
  StartStepTime := Now;

  VarList := TStringList.Create;
  try
    for i := 1 to aos do
      VarList.Add('<Var ' + IntToStr(i) + '>');
    LogTime('VarList gefüllt (' + IntToStr(aos) + ')', StartStepTime);
    StartStepTime := Now;

    // Combobox-Array vorbereiten
    cmbArray[1] := cmb1; cmbArray[2] := cmb2;
    cmbArray[3] := cmb3; cmbArray[4] := cmb4;
    cmbArray[5] := cmb5; cmbArray[6] := cmb6;
    cmbArray[7] := cmb7; cmbArray[8] := cmb8;
    cmbArray[9] := cmb9; cmbArray[10] := cmb10;
    LogTime('Comboboxen Pointer', StartStepTime);
    StartStepTime := Now;

    // Comboboxen befüllen mit StringList
    for i := 1 to 10 do
    begin
      cmbArray[i].Items.Assign(VarList);
      LogTime('Assigned cmb' + IntToStr(i) + ' mit ' + IntToStr(aos) + ' Strings', StartStepTime);
      StartStepTime := Now;
    end;

  finally
    VarList.Free;
    LogTime('Freed VarList', StartStepTime);
  end;

  LogProcedureEnd('--- FormCreate ---');
end; {FormCreate}
Angehängte Grafiken
Dateityp: png ItemIndex - Hauptsoftware.png (59,4 KB, 34x aufgerufen)
Dateityp: png TComboBox - Hauptsoftware.png (82,7 KB, 31x aufgerufen)
Dateityp: jpg TComboBox - Testprogramm.jpg (115,7 KB, 30x aufgerufen)
  Mit Zitat antworten Zitat
shebang

Registriert seit: 7. Feb 2020
151 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Performanceprobleme beim Befüllen von TComboBoxen

  Alt 24. Jul 2025, 15:02
In deinem ersten Log sieht man wunderbar, dass das Problem nur bei den ComboBoxen 1-10 auftritt und nicht bei 11-15. Was ist also der Unterschied zwischen den beiden Gruppen? Ich vermute, dass 1-10 irgendwelche Events verknüpft haben, die nicht triviale Dinge tun.
  Mit Zitat antworten Zitat
m.pritscher

Registriert seit: 24. Jul 2025
6 Beiträge
 
Delphi 10 Seattle Professional
 
#3

AW: Performanceprobleme beim Befüllen von TComboBoxen

  Alt 24. Jul 2025, 15:23
Hi shebang,

danke für die Anmerkung.
11-15 werden einfach nur nicht befüllt mit der Stringliste und bleiben quasi leer. Deshalb geht das setzen des ItemIndex auch so fix
  Mit Zitat antworten Zitat
AuronTLG

Registriert seit: 2. Mai 2018
Ort: Marburg
341 Beiträge
 
Delphi 12 Athens
 
#4

AW: Performanceprobleme beim Befüllen von TComboBoxen

  Alt 24. Jul 2025, 15:41
Ich muss gestehen, ich habe noch nie so viele Einträge in eine ComboBox gehauen, dass ich mir dabei Gedanken um die Geschwindigkeit machen musste.
Hattest du schonmal Items.BeginUpdate/EndUpate um das Assign der ComboBox.Items herum probiert? Bisher scheinst du das nur beim setzen des ItemIndex zu machen.
Bei optischen Komponenten hat das für gewöhnlich einen großen Einfluss auf die Geschwindigkeit, ich bin mir aber gerade nicht sicher, wie sich das Assign diesbezüglich verhält.
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.734 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#5

AW: Performanceprobleme beim Befüllen von TComboBoxen

  Alt 24. Jul 2025, 16:22
Gibt es da vielleicht einen OnChange-Event, der ausgelöst werden könnte? Vielleicht mal testweise alle Events abklemmen?
Thomas Mueller
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.555 Beiträge
 
Delphi 12 Athens
 
#6

AW: Performanceprobleme beim Befüllen von TComboBoxen

  Alt 24. Jul 2025, 17:16
Wirklich SO viel dort anzeigen?

Erstmal BeginUpdate
Delphi-Quellcode:
varList.Items.BeginUpdate;
try
  varList.Items.Clear;
  for i := 1 to 500 do
    varList.Add('<Var ' + IntToStr(i) + '>');
finally
  varList.Items.EndUpdate;
end;
Oder "in einem Schwups" zuweisen.
Delphi-Quellcode:
for i := 1 to 500 do
  stringList.Add('<Var ' + IntToStr(i) + '>');

{ besser nicht, wenn es sehr viel ist ... die ComboBox wäre schnell, aber es wird unschön erst ein langer String gebaut, der dann wieder zerlegt und dann in die Items übergeben }
//varList.Items.Text := stringList.Text; // PS: die nutzen da drin auch BeginUpdate ;)

// oder
varList.Items.Clear;
varList.Items.AddStrings(stringList); // PS: die nutzen da drin auch BeginUpdate ;)
Delphi-Quellcode:
SetLength(arrList, 500);
for i := 1 to 500 do
  arrList[i - 1] := '<Var ' + IntToStr(i) + '>';
varList.Items.Clear;
varList.Items.AddStrings(arrList); // PS: die nutzen da drin auch BeginUpdate ;)



PS: Eine TComboBoxEx kann auch nachträglich befüllt werden.

Bei der TComboBox wird zu Beginn des OnDropDown eine Kopie im DropDown-Fenster geladen/angezeigt,
aber bei TComboBoxEx lässt sich während und auch nach dem Öffnen diese Liste noch bearbeiten.

Dort wäre es z.B. möglich erstmal nur einen Teil zu laden
und wenn der Fokus auf dem letzten Item steht, den Rest, bzw. den nächsten Teil zu laden.



Ich hab mal eine ComboBox gebaut, welche Ports auflistet. (hier war nicht die ComboBox selbst das Langsame, sondern die Datenquelle)
Die wird erst gefüllt/gesucht, wenn der DropDown auf geht. (also wenn nicht nötig, wird auch nicht gesucht)
Und wenn es bei der Suche hängt, dann ist schonmal der bereits gesuchte Teil angezeigt, weiteres taucht nach und nach auf. (die Suche läuft in Threads und beendet sich beim OnCloseUp)


Von DevExpress und Anderen gibt es ComboBoxen, welche einen Filter bieten,
also egal wie viele Zeilen/Datensätze es sind, da wird NIEMALS alles angezeigt. (kann also auch nicht langsam werden)
* z.B. nur die ersten 50
* und via Filter die Auswahl einschränken (davon auch nur die ersten 50)
* auch wenn nicht immer alles da ist, kommt man dennoch an jeden Eintrag dran
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu (24. Jul 2025 um 17:27 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von sakura
sakura

Registriert seit: 10. Jun 2002
Ort: Unterhaching
11.420 Beiträge
 
Delphi 12 Athens
 
#7

AW: Performanceprobleme beim Befüllen von TComboBoxen

  Alt 25. Jul 2025, 05:16
Vielleicht mal testweise alle Events abklemmen?
Das ist auch mein erster Gedanke, das reine Befüllen der TComboBox ist kein Problem, da passiert im Hintergrund nicht wirklich etwas. Ich vermute das Problem auch auf Eurer Seite - Du selbst hast mit dem Testprogramm schon bewiesen, dass es eigentlich kein Problem ist. Selbst wenn Du 100000 Einträge hättest, die Control stört sich daran nicht. Der Nutzer eher

......
Lizbeth W.
Ich bin nicht zurück, ich tue nur so
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke
Online

Registriert seit: 10. Jun 2003
Ort: Berlin
10.055 Beiträge
 
Delphi 12 Athens
 
#8

AW: Performanceprobleme beim Befüllen von TComboBoxen

  Alt 25. Jul 2025, 13:17
Zusätzlich fällt auf, dass auch einfache Operationen wie "ItemIndex := -1" auf diese TComboBoxen
ebenfalls mehrere hundert Millisekunden (ca. 400–500 ms) benötigen.
Das sollte sich doch relativ einfach finden lassen:
Diese Aktion in eine Schleife packen und mehrfach ausführen (also mit unterschiedlichen Indizes). Dann laufen lassen und immer wieder im Debugger anhalten und schauen, was das Programm gerade macht...

Ansonsten gibt es Profiler, mit denen du genau siehst, was da passiert.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
m.pritscher

Registriert seit: 24. Jul 2025
6 Beiträge
 
Delphi 10 Seattle Professional
 
#9

AW: Performanceprobleme beim Befüllen von TComboBoxen

  Alt 28. Jul 2025, 10:41
Zusätzlich fällt auf, dass auch einfache Operationen wie "ItemIndex := -1" auf diese TComboBoxen
ebenfalls mehrere hundert Millisekunden (ca. 400–500 ms) benötigen.
Das sollte sich doch relativ einfach finden lassen:
Diese Aktion in eine Schleife packen und mehrfach ausführen (also mit unterschiedlichen Indizes). Dann laufen lassen und immer wieder im Debugger anhalten und schauen, was das Programm gerade macht...

Ansonsten gibt es Profiler, mit denen du genau siehst, was da passiert.

Beim detaillierten Überprüfen dieses Ansatzes sind wir auf den womöglich "wahren Übeltäter" gestoßen.
Der eigentliche Zeitfresser scheint das "WM_SETREDRAW" zu sein.

Delphi-Quellcode:
// ------------------------- Hauptsoftware ------------------------- //
procedure TFenster_EinstInterfaces2.ClearParVarPanel;
begin
  StartParVarTime := Now;
  LogProcedureStart('--- ClearParVarPanel ---');

  StartStepTime := Now;
  for i := 1 to 15 do
  begin
    hedit := TLabeledEdit(FindComponent('ledt' + IntToStr(i)));
    if hedit <> nil then
    begin
      hedit.Text := '';
      hedit.Hint := sDblClickForVar;
    end;
  end;
  LogTime('ledt-Schleife abgeschlossen', StartStepTime);

  StartStepTime := Now;
  // Redraw deaktivieren (WM_SETREDRAW False)
  for i := 1 to 15 do
  begin
    StartLoopTime := Now;
    hcombo := TComboBox(FindComponent('cmb' + IntToStr(i)));
    LogTime('FindComponent', StartLoopTime);
    if Assigned(hcombo) then
      SendMessage(hcombo.Handle, WM_SETREDRAW, WPARAM(False), 0);
    LogTime('SendMessage redraw', StartLoopTime);
  end;
  LogTime('WM_SETREDRAW false', StartStepTime);

  // Alle Index-Werte in Schleife setzen
  StartStepTime := Now;
  for i := 1 to 15 do
  begin
    hcombo := TComboBox(FindComponent('cmb' + IntToStr(i)));

    if hcombo <> nil then
    begin
      StartLoopTime := Now;
      hcombo.Items.BeginUpdate;
      try
        hcombo.ItemIndex := -1;
      finally
        hcombo.Items.EndUpdate;
      end;
      LogTime('ItemIndex für cmb' + IntToStr(i), StartLoopTime);
    end
    else
    begin
      LogTime('cmb' + IntToStr(i) + ' = nil', StartLoopTime);
    end;
  end;
  LogTime('cmb-Schleife abgeschlossen', StartStepTime);

  StartStepTime := Now;
  // Redraw reaktivieren und Controls invalidieren
  for i := 1 to 15 do
  begin
    hcombo := TComboBox(FindComponent('cmb' + IntToStr(i)));
    if Assigned(hcombo) then
    begin
      SendMessage(hcombo.Handle, WM_SETREDRAW, WPARAM(True), 0);
      RedrawWindow(hcombo.Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_ALLCHILDREN);
    end;
  end;
  LogTime('WM_SETREDRAW true', StartStepTime);

  LogTime('ClearParVarPanel gesamt:', StartParVarTime);
  LogProcedureEnd('--- ClearParVarPanel ---');
end;
Angehängte Grafiken
Dateityp: png Screenshot 2025-07-28 113449.png (86,7 KB, 51x aufgerufen)
Angehängte Dateien
Dateityp: txt logfile - 28-07-2025_10-44-10.txt (4,6 KB, 6x aufgerufen)
  Mit Zitat antworten Zitat
Kas Ob.

Registriert seit: 3. Sep 2023
457 Beiträge
 
#10

AW: Performanceprobleme beim Befüllen von TComboBoxen

  Alt 31. Jul 2025, 12:56
Hi,
Beim detaillierten Überprüfen dieses Ansatzes sind wir auf den womöglich "wahren Übeltäter" gestoßen.
Der eigentliche Zeitfresser scheint das "WM_SETREDRAW" zu sein.
That log makes no sense, it looks like it is missing the reason of its use.

See, you missing core things to isolate, clearly the culprit is your approach with
1) FindComponent ! that thing is slow as turtle, you are repeating it and measuring it again and again....
2) What are these numbers in the scope "[xxx ms]" these makes no sense and not accumulate to the time on the left !?
3) I am afraid that "LogTime" and "LogProcedureEnd" have also something to do with efficient logging.

suggestion :
1) One FindComponent in that code and put them in a list if you want, and also measure it to put it this to rest.
2) Slice that procedure "ClearParVarPanel" into pieces, just simplify it as much as you can, one loop is more than enough, so either make it multiple procedures/functions or reduce it to %30 of its current lines.
3) Use one : either "WM_SETREDRAW" or "BeginUpdate..EndUpdate" but not both, these are messages and they are the same.
Kas
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:18 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz