![]() |
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 |
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.
|
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.
|
AW: ListBox - "OnChange" gesucht
Setzt du zufällig auch TActionList ein?
|
AW: ListBox - "OnChange" gesucht
Zitat:
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. |
AW: ListBox - "OnChange" gesucht
Die ListBox selber bietet keine direkten Notification hierfür, drum hat die TListBox auch kein Event.
![]() 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 ![]() 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. |
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. |
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) |
AW: ListBox - "OnChange" gesucht
Zitat:
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:
Über den ButtonAdd wird der BeispielList ein Objekt mit den notwendigen Daten hinzugefügt. Die Datenhaltung übernimmt die Klasse TBeispielList.
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; 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. |
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: ![]() |
AW: ListBox - "OnChange" gesucht
Zitat:
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:
dann [STRG]+[Shift]+C und private Variable und Setter werden automatisch erstellt.
property speed: Integer;
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:
Solche Event kannst du nach Belieben definieren und nutzen. Ich hoffe das hilft dir das ganze noch etwas zu "verfeinern".
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; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:01 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 by Thomas Breitkreuz