Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi ListBox - "OnChange" gesucht (https://www.delphipraxis.net/204657-listbox-onchange-gesucht.html)

NicoleWagner 16. Jun 2020 15:28

Delphi-Version: 5

ListBox - "OnChange" gesucht
 
Hallo Leute,

gegeben ist eine TListbox. Mit Icons und anderem werden Zeilen hinein- und hinausgeschoben und vertauscht. Ein Button bietet mir an: "Listbox sichern". Jetzt möchte ich gerne, dass die Aufschrift sich verändert in "gesichert", sobald gesichert ist. So weit so fein. Ich erspare mir, das lästige ShowMessage wegzuklicken, das mir den Sicherungserfolg kündet.

Doch: Welches Event ist das meine, wenn ich die Aufschrift wieder zurückändert auf "Listbox sichern", sobald es wieder etwas zu sichern gibt?
"onChange" scheint es nicht zu geben.


Danke für Tips!

Nicole

DieDolly 16. Jun 2020 15:36

AW: ListBox - "OnChange" gesucht
 
Hast du eine zentrale Methode, die dir die Listbox neu bestückt oder sie modifiziert? Wenn ja, würde ich dort anfangen zu suchen.

NicoleWagner 16. Jun 2020 15:38

AW: ListBox - "OnChange" gesucht
 
Danke für die Idee. Das wäre ein dorniger Weg, weil es viele Methoden sind. Trotzdem ein gangbarer, wenn es keinen anderne Weg gäbe. Ich müsste in jede einzelne Methode diese Zeile einfügen.

Jumpy 16. Jun 2020 15:51

AW: ListBox - "OnChange" gesucht
 
Setzt du zufällig auch TActionList ein?

Aviator 16. Jun 2020 16:36

AW: ListBox - "OnChange" gesucht
 
Zitat:

Zitat von NicoleWagner (Beitrag 1467460)
Danke für die Idee. Das wäre ein dorniger Weg, weil es viele Methoden sind. Trotzdem ein gangbarer, wenn es keinen anderne Weg gäbe. Ich müsste in jede einzelne Methode diese Zeile einfügen.

Eigentlich sollte es für das Befüllen der ListBox nur eine zentrale Methode geben die von allen anderen Methoden aufgerufen wird. Demzufolge müsstest du dann nur an einer Stelle das Label oder den Button oder was auch immer aktualisieren.

Ohne deinen genauen Code jetzt zu kennen ist es natürlich schwierig Tipps zu geben. Aber für mich hört sich das ein bisschen danach an, als ob ein Refactoring nicht schaden könnte.

himitsu 16. Jun 2020 17:21

AW: ListBox - "OnChange" gesucht
 
Die ListBox selber bietet keine direkten Notification hierfür, drum hat die TListBox auch kein Event.
https://docs.microsoft.com/en-us/win...-notifications

Wenn/da die ListBox ausschließlich vom eigenen Programm (Delphi) geändert wird, könntest du dich in ListBox.Items reinhängen, was ein TStrings-Nachfahre ist (quasi eine TStringList).
Bei einer ComboBox ist diese Instanz schön gekapselt und lässt sich über eine überschreibbare GetItemsClass leicht austauschen,
aber bei der ListBox ist das leider echt bescheiden implementiert und es wird nicht leicht den Constructor und darin das TListBoxStrings.Create zu ersetzen, um dort die Methoden Insert und Delete zu überschreiben und das neue Event auszulösen.


Bliebe also noch auf Messages zu lauschen.
CB_ADDSTRING und WM_DELETEITEM, wobei Bearbeiten/Ändern über Delete+Insert behandelt wird, also nur Add und Delete zu beachten sind.

Da diese Messages aber über SendMessage laufen, hilft TApplicationEvents.OnMessage nicht, da dort nur PostMessage ankommt und auch nur, wenn es über die MainLoop der VCL eintrudelt. (ist grade eine andere Message-Behandlung aktiv, wie z.B. im MSDN-Library durchsuchenMessageBox, dann geht OnMessage garnicht)
Somit läuft es hier wohl eher auf einen MessageHook hinaus.


Oder eben sich das Event selbst zu implementieren, bei seiner (einen) eigenen ListBox-Befüll-Prozedur.

NicoleWagner 16. Jun 2020 20:02

AW: ListBox - "OnChange" gesucht
 
@himitsu: Danke für die Idee und auch die Links, die mich wieder etwas gelehrt haben, wie dieses Ding mit den bunten Bildern (PC) funktioniert.

Danke auch allen anderen für die Antworten.
Nein, es gibt keine Action List.

Sondern da ist ua. eine Edit-Zeile, die es mir erlaubt, Zeilen "reinzuholen" und "auszutauschen" und "löschen".... Das alles mit Icons. Als ich genau hinsah, waren es nur drei Click-Events die die Box auch veränderten. Was hin- und herkopiert wird, verändert den Listbox-Inhalt nicht.
In die drei Methoden habe ich jetzt die Zeile für die neue Caption hineingeschrieben. Ist ganz nett geworden. Ich sehe sofort, ob ich ungesicherte Inhalte habe oder nicht.

Aviator 17. Jun 2020 07:20

AW: ListBox - "OnChange" gesucht
 
Lagere doch wie von mir vorgeschlagen die Procedure zum Hinzufügen der Items in eine neue Procedure aus. In dieser Procedure setzt du das Label.
In den Klick Events löschst du den Code der mit der neuen Procedure identisch ist und rufst diese stattdessen auf. Zukünftig brauchst du dann immer nur noch an einer Stelle etwas zu ändern.
Die Procedure braucht dann am Parameter eine Ziel-ListBox und den Text der zur Anzeige benutzt werden soll.

Erweiterungsmöglichkeit (wird noch nicht benötigt):
Später kannst du diese Procedure dann ganz leicht überladen damit du an das ListBox Item auch noch ein Objekt mit anhängen kannst.

Stichwort: DRY (Don't Repeat Yourself)

Hobbycoder 17. Jun 2020 07:51

AW: ListBox - "OnChange" gesucht
 
Zitat:

Zitat von NicoleWagner (Beitrag 1467457)
Welches Event ist das meine, wenn ich die Aufschrift wieder zurückändert auf "Listbox sichern", sobald es wieder etwas zu sichern gibt?
"onChange" scheint es nicht zu geben.

Sichere nicht die Listbox. Die Listbox ist eine Visuelle Komponente zur Gestaltung der GUI. Und genau dafür sollte man sie auch nehmen.
Ist ist zwar möglich, aber nicht sinnvoll, diese auch zur Datenhaltung zu nehmen.

Besser ist es, die eigentliche Datenhaltung zum Beispiel in eine eigene Klasse auszulagern, und in einer Routine lediglich die Listbox mit Items zur Anzeige zu füllen.
Du kannst dann in deiner Klasse eigene Events erzeugen, die dann wieder die Routine zum Füllen der ListBox anstoßen, aber auch z.B. einen Button enabled.

Delphi-Quellcode:
Type
  // Erstmal die Datendefinition als Klasse
  TBeispiel=class
  private
    FName: string;
    FFarbe: TColor;
    FAge: Integer;
    proceudre SetName(value: string);
    procedure SetFarbe(value: TColor);
    procedure SetAge(value: Integer);
  published
    property Name: string read FName write SetName;
    property Farbe: TColor read FFarbe write SetFarbe;
    property Age: Integer read FAge write SetAge;
  end;

  // Und eine generische Liste, zur eigentlichen Datenhaltung.
  // TBeispiel und TBeispielList können je nach Umfang natürlich in eine eigene Unit
  TBeispielList=class(TObjectList<TBeispiel>)
  private
    FOnChange: TNotifyEvent;
  public
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
    procedure AddData(sName: string; cFarbe: TColor; iAge: Integer);
  end;

  //Hier eine Miniform
  TForm1=class(TForm)
    ListBox: TListBox;
    ButtonSpeichern: TButton;
    ButtonAdd: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure ButtonAddClick(Sender: TObject);
  private
    BeispielList: TBeispielList;
  public
    procedure DataToGUID(Sender: TObject);
  end;

implementation

//Eine Beispielmethode um Daten in die Liste zu bekommen.
procedure TBeispielList.AddData(sName: string; cFarbe: TColor; iAge: Integer);
var
  b: TBeispiel;
begin
  b:=TBeispiel.create;
  b.Name:=sName;
  b.Farbe:=cFarbe;
  b.Age:=iAge;
  self.Add(b);
  if Assigned(FOnChange) then
    FOnChange(self);
end;

//Alles anderen verbleibt in der Form
procedure TForm1.FormCreate(Sender: TObject);
begin
  BeispielList:=TBeispielList.Create;
  BeispielList.OnChange:=DataToGUI;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  BeispielList.free;
end;

proceudre TForm1.DataToGUI(Sender: TObject);
var
  i: Integer;
begin
  ListBox1.clear;
  for i:=0 to BeispielList.count-1 do
    ListBox1.Items.Add(BeipielList[i].Name);
  ButtonSpeichern.Enable:=True;
end;

procedure TForm1.ButtonAddClick(Sender: TObject);
begin
  BeispielList.AddData('Das ist ein Name', clRed, 30);
end;
Über den ButtonAdd wird der BeispielList ein Objekt mit den notwendigen Daten hinzugefügt. Die Datenhaltung übernimmt die Klasse TBeispielList.
Beim hinzufügen wird das Event OnChange ausgelößt, welches die Aktualisierung der GUI anstößt.
Jetzt kannst du beliebige Methoden der Klasse hinzufügen und immer wenn es notwendig ist, das OnChange auslösen.
Alles weitere geschieht dann automatisch.

NicoleWagner 17. Jun 2020 09:48

AW: ListBox - "OnChange" gesucht
 
@Hobbycoder: Danke für den Code!
Der ist aber fein!
Im Grunde hätte ich den am Anfang gebraucht. Denn was Du so elegant in eine Hülle packst, löste ich im Laufe der sich ergebenden Bedürfnisse mit StringLists, Methodenklassen uam.
Werde das Ding einmal in meine Code-Schnipsel-Bibliothek legen.

Sollte hier jemand eines Tages nach Listboxen suchen, dann hoffe ich, dass es dieses Link noch gibt, das mir viel half:
http://www.tech-ecke.de/index_querei...i/tlistbox.htm

Hobbycoder 17. Jun 2020 10:25

AW: ListBox - "OnChange" gesucht
 
Zitat:

Zitat von NicoleWagner (Beitrag 1467528)
@Hobbycoder: Danke für den Code!
Der ist aber fein!
Im Grunde hätte ich den am Anfang gebraucht. Denn was Du so elegant in eine Hülle packst, löste ich im Laufe der sich ergebenden Bedürfnisse mit StringLists, Methodenklassen uam.
Werde das Ding einmal in meine Code-Schnipsel-Bibliothek legen.

Sollte hier jemand eines Tages nach Listboxen suchen, dann hoffe ich, dass es dieses Link noch gibt, das mir viel half:
http://www.tech-ecke.de/index_querei...i/tlistbox.htm

Immer wieder gerne. Freut mich dir geholfen zu haben. Ist nichts außergewöhnliches.
Ob das nun in die Code-Schnipsel-Bibliothek muss....kann ich nicht beurteilen.
Ich wollte dir damit eines verdeutlichen: Trenne immer GUI von den Daten. Sicherlich kommt man, aus Bequemlichkeit, ab und an in die Versuchung eine sehr kleine Datenstruktur mal in der GUI zu halten. Aber leider rächt sich sowas oftmal irgendwann, wenn das Programm und die Datenstrukturen wachsen.
Weiterhin ist die Wiederverwendbarkeit der Algorithmen an anderen Programmstellen ein wichtiger Aspekt. Aber auch das Debugging gestaltet sich durchweg einfacher, weil man ganz klare Bereiche hat wo man Fehler such muss.
Die Trennung hat zusätzlich den großen Vorteil, dass man auch die direkte Datenmanipulation mittels Private, Public, etc. sehr schön einschränken oder freigeben kann. Heißt, du kannst z.B. durch die Setter bereits vor dem Schreiben eine Variable die Daten auf Plausibilität prüfen und somit auch bestimmte Fehler von vorne herein ausschließen.

Eine Erweiterung der Datenstruktur ist ebenfalls einfacher. Einfach eine neue Property hinzufügen z.B.
Delphi-Quellcode:
property speed: Integer;
dann [STRG]+[Shift]+C und private Variable und Setter werden automatisch erstellt.

Und, was vielleicht für dich noch interessant ist: Du kannst mittels der Events auch gleich Daten an deine GUI mit übergeben.
Beispiel:
Delphi-Quellcode:
Type
  TDataAdd=procdure(Sender: TObject; NewName: string; NewFarbe: TColor; NewAge: Integer) of object;

  TData=class
  private
    FOnDataAdd: TDataAdd;
    procedure DoDataAdd(NewName: string; NewFarbe: TColor; NewAge: integer);
  published
    property OnDataAdd: TDataAdd read FOnDataAdd write FOnDataAdd;
  end;

implementation

TData.DoDataAdd(NewName: string; NewFarbe: TColor; NewAge: integer);
begin
  if Assigned(FOnDataAdd) then
    FOnDataAdd(self, NewName, NewFarbe, NewAge);
end;

TData.IrgendeineMethode;
begin
  //diese Methode wird von irgendwoher aufgerufen
  //und gibt über des Event seine Daten mit
  DoDataAdd(self.FName, self.FFarbe, self.FAge);
end;
Solche Event kannst du nach Belieben definieren und nutzen. Ich hoffe das hilft dir das ganze noch etwas zu "verfeinern".


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:43 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz