Elemente mit Anzeige-/Auswahllisten (ListBox)

Einleitung


ListBox

Listboxen stellen auswählbare Elemente zur Verfügung, z.B. eine Zusammenstellung aller Fahrernamen, Fahrzeuge, etc.

Die Einträge in der Liste lassen sich per Mausklick auswählen. Anschließend ist es möglich, auf den Mausklick zu reagieren und z.B. das ausgewählte Element in einer Meldung anzuzeigen oder anderweitig zu verarbeiten.

Ist die MultiSelect-Eigenschaft aktiviert, sind mehr als ein Eintrag auswählbar. Für zusammenhängende Bereiche hält man nach dem Klick mit der Maus auf das erste Element die <Umschalt>-Taste gedrückt und klickt auf den letzten zu verarbeitenden Eintrag. Alle Elemente zwischen diesen beiden Listenpunkten sind dann markiert.

Die Auswahl nicht direkt benachbarter Einträge erfolgt per Mausklick auf jedes einzelne Element mit gedrückter <Strg>-Taste.

Eine ausführliche Dokumentation zur ListBox gibt es im Internet, z.B. hier


Codebeispiel ListBox

Das folgende Beispiel zeigt den per Doppelklick ausgewählten Listeneintrag in einer Meldung an. Es ist ein Standardcode aus einem Tutorial, weil ich dieses Steuerelement bisher nicht verwendet habe.

procedure TForm1.ListBox1Click(Sender: TObject);
 var
   listBox : TListBox;
   index   : Integer;
 begin
   // Variable mit dem richtigen Objekttyp initialisieren
   listBox := TListBox(Sender);
 
   // Indexnummer in der Liste speichern
   index   := listBox.ItemIndex;
 
   // Den passenden Wert zur Indexnummer in Meldung ausgeben
   ShowMessage(listBox.Items[index]);
 end;


ComboBox

Bei der ComboBox handelt es sich um eine platzsparende Variante der ListBox. Die Programmierung erfolgt auf gleiche Weise. Allerdings belegt die ComboBox nur eine Zeile.

Die hinterlegte Liste mit Elementen erscheint erst per Mausklick auf das meist rechts positionierte Steuerelement (Button) mit Pfeil nach unten. Sie klappt dann nach unten auf.

Die Auswahl eines Elements erfolgt per Mausklick. In der Regel führt diese Aktion dazu, dass die Liste wieder eingeklapt wird.

Eine brauchbare Dokumentation gibt es online, z.B. hier


Codebeispiel ComboBox

Das folgende Beispiel erzeugt ein Formular, mit dem sich für einzelne Fahrer Strafpunkte mit Auswahl eines Vergehens vom Rennleiter vergeben lassen. Die Eingabe eigener Vergehen und Strafpunkte ist möglich.

Das Formular wird dynamisch anhand der Anzahl Teilnehmer aus dem StartCenter generiert. Gibt es drei Fahrer, hat das Formular Felder für die Regler-IDs 1-3, fahren 6 Piloten um den Sieg, gibt es für jeden Starter eine eigene Zeile. Das Formular wird entsprechend größer.

Wer sich jetzt vorstellen kann, wie dieses Formular aussieht, wenn es mit ListBoxen designt ist, hat eine ungefähre Idee, wie sich die Verwendung der ComboBox positiv auf die Größe auswirkt.


var
  form : TForm;
  b : TButton;
  l1 : TLabel;
  l2 : TLabel;
  l3 : TLabel;
  e : array[1..6] of TEdit;
  c : array[1..6] of TComboBox;
  m : array[1..6] of TMemo;
  fine : Boolean;


// =======================================================================
// Eingabeformular für Strafpunkte, die vom Rennleiter verhängt werden
// Das ist z.B. der Fall, wenn der Fahrer seinen Schalter nicht drückt.
procedure StrafpunkteVonRennleiter();
var
  i : Integer;
begin

  // Formular definieren
  form := TForm.Create(nil);
  form.Caption := 'Chaos Rennleiter';
  form.BorderStyle := bsDialog;
  form.SetBounds(200, 100, 570, 410);
  
  // Label für Spaltenköpfe definieren
  l1 := TLabel.Create(form);
  l1.Name := 'Label1';
  l1.Parent := f;
  l1.Caption := 'Slot/ID:';
  l1.Font.Name := 'Impact';
  l1.Font.Size := -16;
  l1.SetBounds(20,20,60,30);
  
  l2 := TLabel.Create(form);
  l2.Name := 'Label2';
  l2.Parent := f;
  l2.Caption := 'Strafkatalog:';
  l2.Font.Name := 'Impact';
  l2.Font.Size := -16;
  l2.SetBounds(100,20,240,30);
  
  l3 := TLabel.Create(form);
  l3.Name := 'Label3';
  l3.Parent := f;
  l3.Caption := 'Punkte:';
  l3.Font.Name := 'Impact';
  l3.Font.Size := -16;
  l3.SetBounds(480,20,140,30);
  
  for i := 1 to cpCountOfSlots do
  begin
  
    // Eingabefeld Slot/ID
    m[i] := TMemo.Create(form);
    with m[i] do
    begin
      Name := 'Memo'+IntToStr(i);
      Parent := f;
      Alignment := taCenter;
      ReadOnly := true;
      WantTabs := false;
      WantReturns := false;
      WordWrap := false;
      Font.Name := 'Impact';
      Font.Size := -20;
      SetBounds(20,60+((i-1)*40),55,35);
    end;

    // Auswahlliste Strafkatalog
    c[i] := TComboBox.Create(form);
    with c[i] do
    begin
      // Feld Merkmale definieren
      Name := 'ComboBox'+IntToStr(i);
      Parent := f;
      Font.Name := 'Impact';
      Font.Size := -20;
      SetBounds(100,60+((i-1)*40),360,35);
      AutoComplete := true;
    end;
    
    // Eingabefeld Strafpunkte
    e[i] := TEdit.Create(form);
    with e[i] do
    begin
      Name := 'Textfeld'+IntToStr(i);
      Parent := f;
      Text := '';
      Font.Name := 'Impact';
      Font.Size := -20;
      SetBounds(480,60+((i-1)*40),60,35);
    end;

  end;
  
  // Button definieren
  b := TButton.Create(form);
  b.Name := 'Button1';
  b.Parent := f;
  b.Font.Name := 'Impact';
  b.Font.Size := -24;
  b.SetBounds(180, 320, 200, 40);
  b.Caption := 'Ab dafür ...';
  b.OnClick := @ButtonClick;
  
  // Formular geöffnet lassen, bis fine true wird
  // Das passiert nach dem Klick auf den Button und
  // ist im Handler @buttonClick definiert
  fine := False;

  // Formular anzeigen
  cpShow(form);       

  // ComboBox mit Einträgen füllen
  for i := 1 to cpCountOfSlots do
  begin
  
    with m[i] do
    begin
      Lines.Add(IntToStr(i));
    end;
    
    with c[i] do
    begin
      // Einträge einfügen
      Items.Add('');
      Items.Add('Causing a collision');
      Items.Add('Pushing another car off the track');
      Items.Add('Unsafe Release');
      Items.Add('Ignoring Blue Flag');
      Items.Add('Jump Start');
      Items.Add('Other - Text eingeben');
      ItemIndex := 0;
      // Es wird etwas ausgewählt
      OnChange := @ComboBoxOnChange;
    end;
    
  end;   // END for - i
  

  // Solange fine den Wert false hat, immer wieder kurz warten
  while not fine do
  begin
    cpSleep(50);
    // Kurz bevor der RBS geschlossen wird (Event BeforeClose), wird die
    // Variable CloseForm gesetzt und das Formular geschlossen, falls es
    // zu diesem Zeitpunkt noch geöffnet ist
    if cpGetIntegerVar('CloseForm') = 99 then
    begin
      fine := True;
    end;
  end;

  // Formular schließen
  cpFormFree(form);  

  end;


// =======================================================================
// Handler, wenn ComboBox Inhalt ausgewählt wurde
procedure ComboBoxOnChange( Sender: TComboBox );
var
  i : Integer;
begin

  // für alle 6 Vergehen Strafpunkte definieren
  for i := 1 to 6 do
  begin
  
    case c[i].ItemIndex of
    
      -1,0 : e[i].Text := '';          // Blank
       1 : e[i].Text := IntToStr(7);   // causing a collision
       2 : e[i].Text := IntToStr(10);  // pushing another car off track
       3 : e[i].Text := IntToStr(6);   // Unsafe Release
       4 : e[i].Text := IntToStr(4);   // Ignoring Blue Flag
       5 : e[i].Text := IntToStr(2);   // Jump Start
       6 : e[i].Text := IntToStr(DefaultStrafpunkteRL);   // Other

    end;   // END case c[i]
    
  end;   // END for - i

end;

    
// =======================================================================
// Handler, wenn Button geklickt wurde
procedure ButtonClick( Sender: TButton );
var
  id : Integer;
  i : Integer;
  PunkteFuerSlot : Integer;
  letzteZeile : Integer;
  fs : TFileStream;
begin
 
  // Für alle IDs durchlaufen
  for i := 1 to cpCountOfSlots do
  begin
  
    m[i].SetFocus;
    letzteZeile := m[i].Lines.Count-1; 
    PunkteFuerSlot := StrToInt( copy(m[i].Lines[letzteZeile], 1, 1) );
    
    // Strafpunkte verteilen
    // Fall 1: Kein Vergehen ausgewählt, keine Punkte eingetragen.
    // Vorgang protokolliert. Keine Auswirkungen für ID
    if (c[i].Text = '') AND (e[i].Text = '') then
    begin
      cpSetStringVar('sVergehen', '');
      cpSetIntegerVar('StrafPunkteSpur', 0);
      Continue;
    end
    // Fall 2: Vergehen ausgewählt, keine Punkte eingetragen.
    // DefaultStrafpunkteRennleiter gehen auf's Konto
    else if (c[i].Text <> '') AND (e[i].Text = '') then
    begin     
      cpSetStringVar('sVergehen', c[i].Text);
      cpSetIntegerVar('StrafPunkteSpur', DefaultStrafpunkteRennleiter);
    end
    // Fall 3: Kein Vergehen ausgewählt, Punkte eingetragen.
    // Eingetragene Punkte gehen auf's Konto
    else if (c[i].Text = '') AND (e[i].Text <> '') then
    begin
      cpSetStringVar('sVergehen', 
                     'Vergehen nicht angegeben, Strafpunkte erhalten.');
      cpSetIntegerVar('StrafPunkteSpur', StrToInt(e[i].Text) );
    end
    // Fall 4: Vergehen ausgewählt, Punkte eingetragen. 
    // ID erhält Strafpunkte auf Konto
    else
    begin
      cpSetStringVar('sVergehen', c[i].Text);
      cpSetIntegerVar('StrafPunkteSpur', StrToInt(e[i].Text) );
    end;

    // Slot einstellen
    Cockpit.Slot := PunkteFuerSlot;
    id := Cockpit.SlotID;
    
    // Punktekonto für gewählte Spur erhöhen
    cpSetIntegerVar('StrafPunkteKontoID'+IntToStr(id), 
                    cpGetIntegerVar('StrafPunkteKontoID'+IntToStr(id)) + 
                    cpGetIntegerVar('StrafpunkteSpur') );
  
    // Punktestand prüfen
    PruefeStrafpunkteStand(PunkteFuerSlot);
      
  // Button gedrückt  
  form.ModalResult := mrOk;
  
  // Fine sorgt für das Schließen des Formulars
  fine := true;
  
end;
...


Dieses Codebeispiel ist am Linden Park Speedway im Einsatz. Kann eine Chaos-Phase direkt einem Fahrer zugeordnet werden, greift ein Chaos-Joker-Strafen-System.

Wird die Strafe durch Eingreifen des Rennleiters verhängt, gibt es einen im Hintergrund geführtes Strafpunktekonto. Nach Erreichen der eingestellten Maximalpunktzahl, erhält der Teilnehmer automatisch eine Strafe.

Die Strafpunkte und das zugewiesene Vergehen exportiert das AddOn in eine Textdatei, die nach Rennende mit einer Tabellenkalkulation ausgewertet werden kann. Diese Teile des Codes sind hier nicht vorhanden.

Durch die Angabe der Gründe, lässt sich später trefflich diskutieren, warum man bestraft wurde und wie sich das auf den Rennausgang ausgewirkt haben könnte.


Hinweise

Bei der ComboBox ist unbedingt die Reihenfolge von Initialisierung des Steuerelements und der eigentlichen Inhalte zu beachten.

Wer die Zeilen oben aufmerksam verfolgt, fragt sich vielleicht, warum die Listenwerte erst definiert werden, nachdem das Formular mit cpShow(form) aufgerufen ist.

Der Grund ist einfach und doch schwer nachvollziehbar. Aber erst, wenn die Elemente definiert sind und das Formular zu sehen ist, ist es möglich, dort Werte zu belegen. Vorher existiert es quasi noch nicht. Resultat ist eine kryptische Fehlermeldung, an der ich fast verzweifelt bin.



Start - FAQ - Glossar - Sitemap - Impressum

 
cockpit-xp/addon/formulare/tlistbox.txt · Zuletzt geändert: 2020/11/28 12:16 (Externe Bearbeitung)