Tech-Ecke / Delphi Inhalt / TListBox

 

     TListBox

 

   Grundlegendes

Der Inhalt einer TListBox Komponente ist vergleichbar mit TStringList, also Strings in mehreren Zeilen.

Die Aufzählung der Zeilen beginnt mit 0, also die erste Zeile ist 0 die zweite Zeile 1 die dritte Zeile 2 und so weiter... Eine Zeile wird in Delphi als Items bezeichnet. Jede einzelne Zeile (Items) für sich betrachtet ist ein String  Ergo, ListBox1.Items[0] ist die erste Zeile der ListBox 1 "und quasi ein String", demzufolge gelten auch alle Operationen die für einen String gelten > siehe Stringoperationen. Tausche dazu einfach das "S" in den Beispielen durch ListBox1.Items[X] (wobei X die Zeile der ListBox ist).

Länge des Textes in einer TListBox-Zeile (Items) ermitteln > siehe Stringoperationen

Inhalt eines in einer TListBox-Zeile (Items) zurechtschneiden > siehe Stringoperationen

Nach einem Zeichen oder Teilstring in einer TListBox-Zeile (Items) suchen > siehe Stringoperationen

Zuweisen von Text ( var S: String;)

   ListBox1.Items.Add ('ich bin ein ListBoxItem');   oder    ListBox1.Items.Add(S);
 

Auslesen einer Zeile ( var S: String;)

   Edit1.Text := ListBox1.Items[0] // liest den Inhalt der ersten Zeile in Edit1
 S := ListBox1.Items[1] // liest den Inhalt der zweiten Zeile in die Variable S
 

Zuweisen einer Integer - Zahl ( var Zahl: Integer; )  [sieh auch > Umwandeln von Variablen]

   ListBox1.Items.Add(IntToStr(Zahl));
 

   Eintrag nur dann hinzufügen wenn dieser nicht vorhanden ist ( var S: String;)

   S := ('hinzufügen wenn nicht bereits vorhanden');
 
if ListBox1.Items.IndexOf(S) = -1 then ListBox1.Items.Add(S);
 

   Löschen einer Zeile (Items)

   ListBox1.Items.Delete(0);  //löscht die erste Zeile
 

   Einfügen einer Zeile (Items)

Dieses Beispiel fügt eine neue Zeile in eine ListBox ein. Die Einfügposition ist die, der zuvor markierten Zeile. Die Markierung wechselt zur eingefügten Zeile. Dabei wird zunächst der gesamte Inhalt der ListBox in eine TStringList (Puffer) geschaufelt, dann alle Einträge nach dem markierten Eintrag von der ListBox gelöscht, die neue Zeile hinzugefügt und anschließend die Einträge nach der Markierung angehangen. Dann wird der Inhalt der ListBox gelöscht und mit dem Inhalt von der TStringList wieder gefüllt.

   var
     i, Pos: Integer;
     Puffer: TStringList;

Puffer := TStringList.Create;
Pos := ListBox1.ItemIndex;
for i := 1 to ListBox1.Items.Count do Puffer.Add(ListBox1.Items[i-1]);
for i := 1 to Puffer.Count - Pos - 1 do Puffer.Delete(Puffer.Count-1);
Puffer.Add('Das ist eine neue Zeile');
for i := 1 to ListBox1.Items.Count - Pos - 1 do Puffer.Add(ListBox1.Items[Pos+i]);
ListBox1.Clear;
for i := 1 to Puffer.Count do ListBox1.Items.Add(Puffer[i-1]);
ListBox1.ItemIndex := Pos + 1;
Puffer.Free;
 

   Kompletten Inhalt löschen

   ListBox1.Items.Clear;  //löscht alle Zeilen
 

   Doppelte Einträge löschen

  n := 0;
while n <= ListBox1.Items.count - 2 do
  begin
      for i := n + 1 to ListBox1.Items.count - 1 do
   begin
if ListBox1.Items[n] = ListBox1.Items[i] then
  begin
      dec(n);
      ListBox1.Items.delete(i);
      break;
   end;
end;
   inc(n);
end;

// Quelle www.delphipraxis.net

   Suchen nach Eintrag

   

var
    Zeile: Integer;

Zeile := ListBox1.Items.IndexOf(
'Suchwort')


// wird ‚Suchwort’ nicht als Eintrag (komplette Zeile) in ListBox1 gefunden ist der Ausgabewert in Variable Zeile -1
// wird ‚Suchwort’ in ListBox1 gefunden, enthält die Variable Zeile die erste Zeile in der ‚Suchwort’ gefunden wird

 

   Inhalt aus Datei laden

   ListBox1.Items.LoadFromFile('Datei.txt'); // hier wäre es angebracht die Anweisung in ein "try except" zu packen > sieh hier
 

   Inhalt in Datei speichern

   ListBox1.Items.SaveToFile('Datei.txt'); // hier wäre es angebracht die Anweisung in ein "try except" zu packen > sieh hier

 ListBox1.Items.SaveToFile('Datei.txt', TEncoding.ASCII); // in ASCII Zeichenkodierung
 ListBox1.Items.SaveToFile('Datei.txt', TEncoding.UTF8); // in UTF8 Zeichenkodierung
 

   Anzahl der Zeilen (Items) ermitteln

   var
    Zeilen: Integer;

Zeilen := ListBox1.Items.Count;
 

   Markierte (selektierte) Zeile (Items) ermitteln

   var
    Zeilen: Integer;

Zeilen := ListBox1.ItemIndex
 

   Markierung (Selektion) aufheben

   ListBox1.ItemIndex := -1;
 

   TPopupMenu einbinden

Zunächst eine TPopupMenu Komponente auf das Form ziehen. Danach bei der entsprechenden ListBox im Objektinspektor unter Ereignisse ins Feld PoupMenu klicken und das entsprechende PopupMenu auswählen. Nun durch einen Doppelklick auf die PopupMenu Komponente einen Eintrag hinzufügen (Objektinsektor muss dazu auf Eigenschaften stehen und der Cursor im Feld Caption stehen). Hinterlegt man nun diesem Eintrag eine Procedure (siehe TMainMenu) so kann in dieser die angewählte Zeile abfragen. Das geht so:

   Edit1.Text := ListBox1.Items[ListBox1.ItemIndex]  // in Edit1 wird nun der Inhalt von der ausgewählten ListBox Zeile ausgegeben
 

   Mit Rechtsklick markieren

Möchte man mit einem Rechtsklick, auch gleich die entsprechende ListBoxZeile markieren, dann hinterlegt man folgende Programmzeilen, hinter das Ereignis OnMouseDown (Objektinspektor -> Ereignisse zur entsprechenden ListBox):

Bitte beachte, dass die mit dem Hinweis versehene Zeile nur dann benötigt wird, wenn auch ein PopUpMenue vorhanden ist, ansonsten verursacht diese Zeile einen Zugriffsfehler.

   var
    
cursorpos : TPoint;
     ndx : integer;


if Button=mbRight then
begin
     cursorpos.X := X;
     cursorpos.Y := y;
     ndx := ListBox1.ItemAtPos(cursorpos,true);

     if (ndx <> -1) then
          begin
               with (Sender as TListBox) do
                    begin
                         Selected[ndx] := True;
                         cursorpos := ClientToScreen(cursorpos);
                         PopupMenu.Popup(cursorpos.x + Left,cursorpos.Y+
10); //<- nur wenn auch ein PopUpMenue vorhanden ist !!!
          end;
     end;
end;
 

   Drag & Drop

Um Einträge von einer zur anderen ListBox per Drag & Drop zu kopieren, muss man drei Schritte erledigen. Im folgenden Beispiel wird zunächst davon ausgegangen dass man Einträge von ListBox1 zur ListBox2 kopieren möchte.

Schritt 1.) Bei der sendenden ListBox (Quelle) muss im Objektinspektor/Eigenschaften DragMode auf dmAutomatic stehen

 

Schritt 2.)

Bei der empfangenden ListBox (Ziel) im Objektinspektor/Ereignisse für OnDragOver  eine Procedure erstellen (Doppelklick auf das leere Feld dahinter)  und folgenden Code schreiben:

Accept := True;

 

Schritt 3.) Bei der empfangenden ListBox (Ziel) im Objektinspektor/Ereignisse für OnDragDrop  eine Procedure erstellen (Doppelklick auf das leere Feld dahinter)  und folgenden Code schreiben:  (benötigt Variabelendeklaration: var Eintrag : string;)

Eintrag := ListBox1.items[ListBox1.Itemindex];   // kopiert gezogenen Eintrag in die Variable Eintrag
ListBox2.Items.Add(Eintrag);  
// fügt den Text in Variable Eintrag der Liste als neuen Eintrag hinzu

Im Großen und Ganzen war's das schon, jedoch könnten folgende Ergänzungen noch recht interessant sein.

Zu Schritt 2.)

mit Accept := True; wird prinzipiell festgelegt, das die Quelle beliebiger Herkunft sein darf, also auch von einer anderen ListBox als ListBox2 oder gar einer Komponente. Um diese Freiheit auszunutzen muss man allerdings unter Schritt 3 einen anderen Code hinterlegen aber dazu weiter unten mehr. Man kann hier die Quelle aber auch schon einschränken. z.B. durch verwenden von:

   if Source is TListBox then Accept := True;   // Hier wird festgelegt, dass die Quelle eine TListBox sein muss.
 

Zu Schritt 3.)

Mit dem oben im Beispiel gezeigtem Code ist die Quelle und das Ziel quasi festgelegt. Möchte man jedoch die Quelle hier nicht festlegen, um z.B. mehrere ListBox'en als mögliche Quelle zu nutzen, so könnte der Code wie folgt aussehen:

   Eintrag := (Source as TListBox).Items[(Source as TListBox).ItemIndex];
 

Oder man möchte z.B. ein TEdit als Ziel nutzen. Dann führt man die Schritte 1 und 2 an einer TEdit durch und unter Schritt 3 könnte die zweite Zeile so aussehen:

   Edit1.Text := (Source as TListBox).Items[(Source as TListBox).ItemIndex]
 

   Verschieben von Items innerhalb einer ListBox
 

Verschieben mittels Drag&Drop:

Zunächst muss man im Objektinspektor den "dragMode" der betreffenden ListBox auf dmAutomatic setzen. Dies ist quasi das Einschalten der Funktionalität Drag&Drop. Damit nur Einträge innerhalb der ListBox akzeptiert werden schreibt man hinter dem Ereignis OnDragOver folgenden Code:

   if Source <> ListBox1 then
 Accept := FALSE
 

Und zum Schluss noch der Code für das eigentliche verschieben, hinter dem Ereignis OnDragDrop: (var von, nach: Integer;)

   if Source = ListBox1 then
    begin

       von := ListBox1.ItemIndex;
       nach := ListBox1.ItemAtPos(Point(X, Y), TRUE);
 
      if nach = -1 then nach := ListBox1.Items.Count-1;
       ListBox1.Items.Move(von, nach);
 
   end;
 

 

Verschieben mittels Up- und Down-Button:

Wie bei der Drag&Drop-Methode muss auch hier die Eigenschaft "dragMode" auf dmAutomatic gesetzt werden.

  // verschiebe Item in ListBox aufwärts
procedure
ListBoxItemUp(AListBox: TListBox);
var
   CurrIndex: Integer;
begin
   with AListBox
do
      if ItemIndex > 0 then
         begin
            CurrIndex := ItemIndex;
            Items.Move(ItemIndex, (CurrIndex - 1));
            ItemIndex := CurrIndex - 1;
         end;
end;

// verschiebe Item in ListBox abwärts
procedure
ListBoxItemDown(AListBox: TListBox);
var
   CurrIndex, LastIndex: Integer;
begin
   with AListBox
do
      begin
         CurrIndex := ItemIndex;
         LastIndex := Items.Count;
         if ItemIndex <> -1 then
            begin
               if CurrIndex + 1 < LastIndex then
                  begin
                     Items.Move(ItemIndex, (CurrIndex + 1));
                     ItemIndex := CurrIndex + 1;
                  end;
            end;
      end;
end;

 

Hinter den gewünschten Buttons folgenden Code hinterlegen:

  ListBoxItemUp(ListBox1);  // noch oben verschieben

ListBoxItemDown(ListBox1);  // nach unten verschieben

 

 

  ListBox mit einem BMP vor jedem Eintrag

Um die Optik der sonst recht schlichten TListBox etwas aufzupeppen kann z.B. vor jeden Eintrag ein BMP-Icon setzen. Und so geht's:Zunächst sollten folgende beiden Einstellungen zur betreffenden ListBox im Objektinspektor vorgenommen werden:

     Style auf  lbOwnerDrawFixed setzen   und bei ItemHeight die Pixelhöhe des BMP's angeben, bzw. 2 Pixel mehr angeben...

Danach folgenden Code in der entsprechenden Unit platzieren:

  procedure DrawListBoxEx(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState);
const
          Col2:
array [Boolean] of TColor = (clInactiveCaptionText, clWindowText);
var
      Bmp: TBitmap;
      TopDif: Integer; // Gleicht die Höhendifferenz aus
begin
   Bmp := TBitmap.Create;
   try
   with (Control as TListbox) do
      begin
         Bmp.Transparent := True;

         // Hier Beispiel  um Bitmap von Festplatte laden
        
Bmp.LoadFromFile('c:\DeinBild.bmp');

         if odSelected in State then
            Canvas.Font.Color := clCaptionText
         else
            Canvas.Font.Color := Col2[(Control as TListbox).Enabled]; // tauschen wenn farbige Items gewünscht, siehe hier !

         TopDif := (ItemHeight
div 2) - (Canvas.TextHeight(#32) div 2);
         Canvas.TextRect(Rect, Rect.Left + Bmp.Width + 1, Rect.Top + TopDif, Items[Index]);
         Canvas.Draw(Rect.Left, Rect.Top, Bmp);
      end
   finally
   Bmp.Free;
   end;
end;

Quelle: Delphi-Library.de

Dann muss das Zeichnen der Einträge noch angestoßen werden. Hier im Beispiel hinter dem ListBox-Event OnDrawItem.

  DrawListBoxEx(Control, Index, Rect, State); 
 

 

   ListBox mit farbigen einträgen

Eine weitere Möglichkeit um eine ListBox ein wenig aufzupeppen ist, das einfärben von einzelnen Einträgen. Dazu muss zunächst im Objektinspektor das Style auf  lbOwnerDrawFixed setzen.
Beim Ereignis
OnDrawItem wird dann folgender Code hinterlegt:

  with Control as TListBox do
  
begin
    
Canvas.FillRect(Rect);
    Canvas.Font.Color := TColor(Items.Objects[Index]);
    Canvas.TextOut(Rect.Left +
2, Rect.Top, Items[Index]);
  
end;
 

Die einzelnen farbigen Items werden dann wie folgt hinzugefügt:

  ListBox1.Items.AddObject('Ich bin rot', Pointer(clRed));
ListBox1.Items.AddObject(
'Ich bin blau', Pointer(clBlue));
 

Möchte man farbige Einträge mit "BMP's vor jedem Item" kombinieren, so wird die entsprechend markierte Zeile im Quelltext gegen folgende Zeile getauscht:

  Canvas.Font.Color := TColor(Items.Objects[Index]);
 

"Die Option Drucken funktioniert erst ab Netscape V4.0 bzw. I-Explorer 5.0 !"

[letzte Aktualisierung 21.09.2008]