Caption einer ComboBox zurücksetzen. [GELÖST]

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
AlphaInc.
Beiträge: 5
Registriert: Mi 28. Apr 2021, 22:17

Caption einer ComboBox zurücksetzen. [GELÖST]

Beitrag von AlphaInc. »

Hey,

Ich hab ein kleines Tool geschrieben, der als Videospiele Launcher fungiert (Mods oder andere Erweiterungen laden, Sprache ändern, etc.). Mit einer ComboBox soll der User die Größe des Launchers ändern können. Das funktioniert soweit alles einwandfrei. Nun versuche ich, die Caption der ComboBox zurück zusetzen, sobald ein Menüpunkt ausgewählt wurde. Das Problem das ich habe ist nur, dass sobald ein Menüpunkt ausgewählt wurde, die ComboBox einfach leer wird (sprich keine Caption). Andere Menüpunkte auswählen ist weiterhin möglich. Nach jeder Auswahl eines neuen Menüpunktes wird eine Prozedur gestartet, die zusätzlich einen Eintrag in einer .INI checkt. Ich habe bereits versucht die ComboBox1.ItemIndex:=-1 zu setzen, ohne Erfolg. Hier ist mein Code:

Code: Alles auswählen

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls,
  Buttons, FileUtil, IniFiles;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    ComboBox1: TComboBox;

    procedure Button1Click(Sender: TObject);
    procedure ComboBox1Change(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure confCheck();

  private

  public

  end;

var
  Init, Language, Version, Enhancements, Mods, Size, Custom: String;
  BackgroundList: TStrings;
  MusicList: TStrings;
  LogoList: TStrings;
  Form1: TForm1;
  Faktor: extended;
  Config: TIniFile;

implementation

{$R *.lfm}

{ TForm1 }

const
   IniFile = 'conf.ini';

procedure TForm1.FormCreate(Sender: TObject);
begin

end;

procedure TForm1.ComboBox1Change(Sender: TObject);
begin
  case ComboBox1.ItemIndex of
    0: begin
          Config := TIniFile.Create(IniFile);
          try
             Config.WriteString('Size', 'Size', 'XL');
          finally
            Config.free;
          end;
    end;
    1: begin
          Config := TIniFile.Create(IniFile);
          try
             Config.WriteString('Size', 'Size', 'L');
          finally
            Config.free;
          end;
    end;
    2: begin
          Config := TIniFile.Create(IniFile);
          try
             Config.WriteString('Size', 'Size', 'M');
          finally
            Config.free;
          end;
    end;
    3: begin
          Config := TIniFile.Create(IniFile);
          try
             Config.WriteString('Size', 'Size', 'S');
          finally
            Config.free;
          end;
      end;
   end;
   confCheck;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
   Close();
end;

procedure TForm1.confCheck();
begin
   Config := TIniFile.Create(IniFile);
   try
      Language     :=Config.ReadString('Language', 'Language', '');
      Size         :=Config.ReadString('Size', 'Size', '');

      //Setting of Tool-Size
      if Size='XL' then
         begin
            Faktor:=1;
         end
      else if Size='L' then
         Faktor:=1.6
      else if Size='M' then
         Faktor:=2.4
      else if Size='S' then
         Faktor:=3.6;

      //Dynamic Tool-Size
      Width:=round(Screen.Width/Faktor);
      Height:=round(Screen.Height/Faktor);

      //Positioning of Tool-Size
      Form1.position := poScreenCenter;
      Form1.BorderStyle := bsNone;

      //Setting of Captions
      if Language='German' then
         begin
            ComboBox1.Text:='Größe wählen';
            ComboBox1.Items.Clear;
            ComboBox1.Items.Add('Vollbildschirm');
            ComboBox1.Items.Add('Größe L');
            ComboBox1.Items.Add('Größe M');
            ComboBox1.Items.Add('Größe S');
         end
      else if Language='English' then
         begin
            ComboBox1.Text:='Choose Size';
            ComboBox1.Items.Clear;
            ComboBox1.Items.Add('Fullscreen');
            ComboBox1.Items.Add('Size L');
            ComboBox1.Items.Add('Size M');
            ComboBox1.Items.Add('Size S');
         end;
      ComboBox1.ItemIndex:=-1;
   finally
      Config.free;
   end;
end;

end.
Sieht jemand den Grund, warum die Caption nicht zurückgesetzt wird und einfach leer wird, nachdem ein Menüpunkt ausgewählt wird?

Edit: Wenn ich einen Button implementiere, der einfach nur die Prozedur ConfCheck ausführt, dann wird die Caption komischerweise zurückgesetzt aber nicht über die ComboBox selbst.
Zuletzt geändert von AlphaInc. am Fr 30. Apr 2021, 22:34, insgesamt 1-mal geändert.

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1432
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Caption einer ComboBox zurücksetzen.

Beitrag von fliegermichl »

Du musst zuerst die Texte den Items zuordnen und danach die Eigenschaft Text bzw. Itemindex setzen.

AlphaInc.
Beiträge: 5
Registriert: Mi 28. Apr 2021, 22:17

Re: Caption einer ComboBox zurücksetzen.

Beitrag von AlphaInc. »

Erstmal danke für die Antwort.
Und auch direkt sorry für die nächste dumme Frage, wie ordne ich Text und Items zu?

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1432
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Caption einer ComboBox zurücksetzen.

Beitrag von fliegermichl »

Na du hast doch in confCheck die Combobox.Items.Add(... Zeilen und vorher die Zuweisung Combobox.Text :=

Das musst du nur rumdrehen. Zuerst die Items.Add Dinger und danach dann die Textzuweisung

AlphaInc.
Beiträge: 5
Registriert: Mi 28. Apr 2021, 22:17

Re: Caption einer ComboBox zurücksetzen.

Beitrag von AlphaInc. »

Ah hatte das falsch verstanden. Okay, das habe ich getan, aber die Caption ist immer noch leer, nachdem ich einen Menüpunkt der ComboBox ausgewählt habe

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1432
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Caption einer ComboBox zurücksetzen.

Beitrag von fliegermichl »

Wenn die Combobox den Style csDropDownlist hat, dann kann man den Text nicht direkt zuweisen sondern muss Combobox.ItemIndex auf einen Wert größer oder gleich 0 setzen.

AlphaInc.
Beiträge: 5
Registriert: Mi 28. Apr 2021, 22:17

Re: Caption einer ComboBox zurücksetzen.

Beitrag von AlphaInc. »

Der Style ist auf csDropDown gestellt (ohne List am Ende).

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1432
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Caption einer ComboBox zurücksetzen.

Beitrag von fliegermichl »

Hab jetzt grad nochmal auf deinen Code geschaut.
Du vermischst doch da Äpfel mit Birnen.
In Combobox1Change prüfst du auf Größenangaben (XL, L, M, S) und schreibst diese Werte
in das ini File.

In confCheck vergleichst du dann Languages, die aber nirgends gesetzt werden und deshalb wird ItemIndex auf -1 gesetzt und somit nichts angezeigt.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Caption einer ComboBox zurücksetzen.

Beitrag von wp_xyz »

Im beigefügten Projekt habe ich deinen Code auf das nötige reduziert. Du hast hier die etwas ungewöhnliche Situation, dass du im OnChange-Ereignis der Combobox die Methode ConfCheck() aufrufst, in der ggfs die Items neu befüllt werden - zum Glück löst das Neufüllen der Items seiterseits kein weiteres OnChange hervor, sonst wäre das der erste Schritt für einen Hänger. Aber OnChange reagiert anscheinend nur auf Benutzereingaben. Trotzdem: offenbar ist die Combobox mit der Abarbeitung der Aktionen, die durch die Auswahl eines anderen Eintrags angestoßen wurden, mit dem OnChange-Ereignis noch nicht zu Ende - aber ausgerechnet dort ziehst du der Combobox den Boden unter den Füßen weg, löschst die Liste und trägst neue Einträge ein, so das ganze nicht wunschgemäß funktioniert.

Ich meine, das ganze sollte funktionieren, wenn du den Change-Vorgang zu Ende arbeiten lässt und dann erst ConfCheck aufrufst. Es gibt für sowas die Methode QueryAsyncCall der Application-Klasse. Dort kann man eine spezielle Methode angeben, die in die Ereigniswarteschlange des Betriebssystem eingereiht und erst dann abgearbeitet wird, wenn die Anwendung idle ist (also insbesondere das Change zu Ende gekommen ist). (Ich meine es gibt dafür auch eine Methode von TControl, aber ich finde die gerade nicht...)

Ich habe das im beigefügten Demo eingebaut, und - es funktioniert: Nach der Auswahl eines Combo-Eintrags erscheint wieder der Text "Größe wählen", was du offenbar beabsichtigst (ist allerdings in meinen Augen eine verwirrende Benutzerführung, denn dieser erwartet eigentlich den angewählten Eintrag zu sehen).

Letztendlich programmierst du hier etwas nach, was in Laz-trunk in der Property TextHint realisiert ist. Das ist ein Hinweistext, der in einigen Controls angezeigt sind, wenn sie keinen Inhalt tragen. Falls du also Laz-Trunk verwendest, könntest du in Combobox.TextHint deinen Hinweis "Größe wählen" eintragen, und musst nur sicherstellen, dass in OnChange Combobox.Text wieder gelöscht wird (denn TextHint erscheint nur bei leerem Control). Offenbar ist hier das Ereignis-Handling weniger kritisch, denn das ganze funktioniert auch direkt, ohne den Umweg über QueryAsyncCall.

In meinem Beispielprojekt wird dieser Fall ebenfalls abgehandelt, in Combobox2. Der Code ist allerdings nur für Trunk aktiv.
Dateianhänge
forum_combobox_caption.zip
(2.23 KiB) 47-mal heruntergeladen

AlphaInc.
Beiträge: 5
Registriert: Mi 28. Apr 2021, 22:17

Re: Caption einer ComboBox zurücksetzen.

Beitrag von AlphaInc. »

wp_xyz hat geschrieben:
Fr 30. Apr 2021, 11:24
Im beigefügten Projekt habe ich deinen Code auf das nötige reduziert. Du hast hier die etwas ungewöhnliche Situation, dass du im OnChange-Ereignis der Combobox die Methode ConfCheck() aufrufst, in der ggfs die Items neu befüllt werden - zum Glück löst das Neufüllen der Items seiterseits kein weiteres OnChange hervor, sonst wäre das der erste Schritt für einen Hänger. Aber OnChange reagiert anscheinend nur auf Benutzereingaben. Trotzdem: offenbar ist die Combobox mit der Abarbeitung der Aktionen, die durch die Auswahl eines anderen Eintrags angestoßen wurden, mit dem OnChange-Ereignis noch nicht zu Ende - aber ausgerechnet dort ziehst du der Combobox den Boden unter den Füßen weg, löschst die Liste und trägst neue Einträge ein, so das ganze nicht wunschgemäß funktioniert.

Ich meine, das ganze sollte funktionieren, wenn du den Change-Vorgang zu Ende arbeiten lässt und dann erst ConfCheck aufrufst. Es gibt für sowas die Methode QueryAsyncCall der Application-Klasse. Dort kann man eine spezielle Methode angeben, die in die Ereigniswarteschlange des Betriebssystem eingereiht und erst dann abgearbeitet wird, wenn die Anwendung idle ist (also insbesondere das Change zu Ende gekommen ist). (Ich meine es gibt dafür auch eine Methode von TControl, aber ich finde die gerade nicht...)

Ich habe das im beigefügten Demo eingebaut, und - es funktioniert: Nach der Auswahl eines Combo-Eintrags erscheint wieder der Text "Größe wählen", was du offenbar beabsichtigst (ist allerdings in meinen Augen eine verwirrende Benutzerführung, denn dieser erwartet eigentlich den angewählten Eintrag zu sehen).

Letztendlich programmierst du hier etwas nach, was in Laz-trunk in der Property TextHint realisiert ist. Das ist ein Hinweistext, der in einigen Controls angezeigt sind, wenn sie keinen Inhalt tragen. Falls du also Laz-Trunk verwendest, könntest du in Combobox.TextHint deinen Hinweis "Größe wählen" eintragen, und musst nur sicherstellen, dass in OnChange Combobox.Text wieder gelöscht wird (denn TextHint erscheint nur bei leerem Control). Offenbar ist hier das Ereignis-Handling weniger kritisch, denn das ganze funktioniert auch direkt, ohne den Umweg über QueryAsyncCall.

In meinem Beispielprojekt wird dieser Fall ebenfalls abgehandelt, in Combobox2. Der Code ist allerdings nur für Trunk aktiv.
Danke vielmals, das war genau das was ich wollte.

Antworten