Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Zur Laufzeit Comboboxen hinzufügen (https://www.delphipraxis.net/203408-zur-laufzeit-comboboxen-hinzufuegen.html)

KomischerKautz 14. Feb 2020 09:16

Delphi-Version: 7

Zur Laufzeit Comboboxen hinzufügen
 
Hallo,
ich würde gerne zur Laufzeit meines Programms per Buttonclick Comboboxen hinzufügen, dabei soll bei jedem weiteren Click eine neue Combobox unter der vorherigen angehängt werden.
Wie kann ich das am besten realisieren?

AuronTLG 14. Feb 2020 09:35

AW: Zur Laufzeit Comboboxen hinzufügen
 
Es gibt zwei Möglichkeiten.

1. Wenn, wie bei deinem anderen Thread, die Anzahl der möglichen Comboboxen limitiert ist, kannst du sie wie da schon vorher im Designermodus auf die Form legen und dann nach und nach sichtbar schalten.

2. Ist dies nicht der Fall, so musst du mit dynamischen Komponenten arbeiten, d.h. du kreierst die Comboboxen zur Laufzeit selbst.

Dies sähe z.B. so aus:

Code:
Procedure KreiereComboBox;
Var ACombobox : TComboBox;

Begin
AComboBox := TComboBox.Create(GroupBox1);
AComboBox.Parent := GroupBox1;
AComboBox.Height := 14;
AComboBox.Width := 50;
AComboBox.Left  := 5;
AComboBox.Top   := 10;

AComboBox.Items.Add('Bla');
AComboBox.Items.Add('Bla');
AComboBox.Items.Add('Bla');
AComboBox.ItemIndex := 0;

AComboBox.Name    := 'XYZComboBox';
AComboBox.OnChange := BlaBlaBlubChange;
End;
Im Prinzip kreierst du die ComboBox als Variable und modifizierst sie so wie du sie brauchst, also Items einfügen, Größe und Position festlegen, Ereignisse verknüpfen etc.

Willst du später auf diese ComboBoxen nochmal zugreifen, ist es am sinnvollsten, diese dynamisch erzeugten Comboboxen z.B. in einer Liste abzuspeichern, um einen einfachen Zugriff zu haben, da diese im Gegensatz zum im Designer erzeugten Komponenten nicht direkt ansprechbar sind.

Luckie 14. Feb 2020 10:58

AW: Zur Laufzeit Comboboxen hinzufügen
 
Man sollte aber noch den Parent setzen, damit sie auch gezeichnet wird und den Owner, damit der Owner das Zerstören übernimmt.

KodeZwerg 14. Feb 2020 11:53

AW: Zur Laufzeit Comboboxen hinzufügen
 
Hier ein konstrukt wie man evtl an solch eine sache rangehen könnte.
Nur im Notepad geschrieben, also ungetestet!
Delphi-Quellcode:
var
  Form1: TForm1;
  cbList: TList;

implementation

// wenn als click-event, dann sollte hier nur die cbList initialisiert werden und im click dann einfach adden
procedure TForm1.FormCreate(Sender: TObject);

var i: integer
   cb: TComboBox;  
begin
  cbList := TList.Create;
  for i := 0 to 9 do
  begin
    cb := TComboBox.Create(self);
    cb.Parent := self;
    cb.Top := (i * (cb.Height + 3));
    // weitere optionen setzen
    cbList.Add(cb);
  end;

  // als beispiel alle boxen mit text versehen:
  for i := 0 to cbList.Count-1 do
    TComboBox(cbList[i]).Text := Format('ComboBox %d', [i]);

end;
Ich hoffe es hilft, im close event halt die cbList durchiterieren und .Free ranpappen.

himitsu 14. Feb 2020 11:58

AW: Zur Laufzeit Comboboxen hinzufügen
 
Der trauchige Witz ist, dass in der VCL sich auch der Parent um die Freigabe kümmert. (vermutlich auch im FMX der selbe Mist, aber hab mich nicht getraut nachzusehn)

AuronTLG 14. Feb 2020 12:04

AW: Zur Laufzeit Comboboxen hinzufügen
 
Ach genau, Parent vergessen. Habs angepasst.
Ja, in FMX isses genauso, muss man auch Parent und Owner festlegen.
Mit dynamischen Komponenten zu arbeiten macht unglaublich viel Spaß. Deswegen greife ich für gewöhnlich auf TFrames zurück, wenn es nicht nur um einzelne Komponenten geht. Das macht die Sache deutlich angenehmer.

KodeZwerg 14. Feb 2020 12:30

AW: Zur Laufzeit Comboboxen hinzufügen
 
Zitat:

Zitat von Frühlingsrolle (Beitrag 1457504)
Zitat:

[...] Comboboxen hinzufügen, dabei soll bei jedem weiteren Click eine neue Combobox unter der vorherigen angehängt werden.
Noch erfüllt keins der Beispiele diese Anforderung. Das Prinzip ist aber ersichtlich.

Für meins dann so in etwa... bezeichner könnten falsch sein, immer noch nur notepad..
Delphi-Quellcode:
var
  Form1: TForm1;
  cbList: TList;

implementation

procedure TForm1.FormCreate(Sender: TObject);
begin
  cbList := TList.Create;
end;

procedure TForm1.Button1Click(Sender: TObject);
var cb: TComboBox;
begin
  cb := TComboBox.Create(self);
  cb.Parent := self;
  cb.Top := (cbList.Count * (cb.Height + 3));
  // weitere eigenschaften setzen
  cbList.Add(cb);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var i: integer;
begin
// einfach mal testen ob's nötig ist, ich möchte mich nicht festlegen
  for i := 0 to cbList.Count-1 do
    TComboBox(cbList[i]).Free;
  cbList.Free;
end;

KomischerKautz 14. Feb 2020 12:44

AW: Zur Laufzeit Comboboxen hinzufügen
 
Zitat:

Zitat von KodeZwerg (Beitrag 1457508)
Zitat:

Zitat von Frühlingsrolle (Beitrag 1457504)
Zitat:

[...] Comboboxen hinzufügen, dabei soll bei jedem weiteren Click eine neue Combobox unter der vorherigen angehängt werden.
Noch erfüllt keins der Beispiele diese Anforderung. Das Prinzip ist aber ersichtlich.

Für meins dann so in etwa... bezeichner könnten falsch sein, immer noch nur notepad..
Delphi-Quellcode:
var
  Form1: TForm1;
  cbList: TList;

implementation

procedure TForm1.FormCreate(Sender: TObject);
begin
  cbList := TList.Create;
end;

procedure TForm1.Button1Click(Sender: TObject);
var cb: TComboBox;
begin
  cb := TComboBox.Create(self);
  cb.Parent := self;
  cb.Top := (cbList.Count * (cb.Height + 3));
  // weitere eigenschaften setzen
  cbList.Add(cb);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var i: integer;
begin
// einfach mal testen ob's nötig ist, ich möchte mich nicht festlegen
  for i := 0 to cbList.Count-1 do
    TComboBox(cbList[i]).Free;
  cbList.Free;
end;


Super! Das funktioniert einwandfrei. Vielen Dank für euere Hilfe!
Nun abschließend noch; den Inhalt von Comboboxen fülle ich ja normalerweise in der StringList der Combobox in den Properties. Das funktioniert hier wie es scheint nicht, da ja noch keine Combobox vorhanden ist, welche ich füllen kann.
Wie kann ich nun den Inhalt aller erzeugter Comboboxen vorbestimmen?

mkinzler 14. Feb 2020 13:06

AW: Zur Laufzeit Comboboxen hinzufügen
 
In dem du den Wert zur Laufzeit hinzufügst bzw. setzt. (ComboBox.Items)

DeddyH 14. Feb 2020 13:07

AW: Zur Laufzeit Comboboxen hinzufügen
 
Zitat:

Zitat von KodeZwerg (Beitrag 1457508)
Zitat:

Zitat von Frühlingsrolle (Beitrag 1457504)
Zitat:

[...] Comboboxen hinzufügen, dabei soll bei jedem weiteren Click eine neue Combobox unter der vorherigen angehängt werden.
Noch erfüllt keins der Beispiele diese Anforderung. Das Prinzip ist aber ersichtlich.

Für meins dann so in etwa... bezeichner könnten falsch sein, immer noch nur notepad..
Delphi-Quellcode:
var
  Form1: TForm1;
  cbList: TList;

implementation

procedure TForm1.FormCreate(Sender: TObject);
begin
  cbList := TList.Create;
end;

procedure TForm1.Button1Click(Sender: TObject);
var cb: TComboBox;
begin
  cb := TComboBox.Create(self);
  cb.Parent := self;
  cb.Top := (cbList.Count * (cb.Height + 3));
  // weitere eigenschaften setzen
  cbList.Add(cb);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var i: integer;
begin
// einfach mal testen ob's nötig ist, ich möchte mich nicht festlegen
  for i := 0 to cbList.Count-1 do
    TComboBox(cbList[i]).Free;
  cbList.Free;
end;

Im FormCreate Liste erzeugen und im FormClose freigeben? Viel Spaß bei der Fehlersuche. Und wie schon mehrfach erwähnt muss man die Komponenten nicht selbst freigeben, wenn man ihnen einen Owner und/oder einen Parent zugewiesen hat.

haentschman 14. Feb 2020 13:24

AW: Zur Laufzeit Comboboxen hinzufügen
 
Moin...:P
...nur zur Sicherheit: Delphi-Version: 7 :gruebel:
Hast du die Möglichkeit auf die aktuelle Community Edition zu wechseln? Ich tippe darauf, daß du mit dem Lernen noch am Anfang stehst. :wink:

Rolf Frei 14. Feb 2020 13:28

AW: Zur Laufzeit Comboboxen hinzufügen
 
Seit wann ist der Parent für die Freigbae zuständig?! Das wird über den Owner gesteuert und nicht über den Parent. Wenn der Parent freigegeben wird, ist das enhaltene Objekt nach wie vor vorhanden und kann einfach an einen anderen Parent angehängt werden. Würde das durch den Parent gesteuert, würde viel eigener Code nicht mehr laufen, da ich in der Regel solche Sachen selber im Constructor erstelle und ich da keinen Owner im Create angebe. So hat man die volle Kontrolle über den Lebenszyklus einer eigenen Komponente und kann diese im Destructor der Komponente, innerhalb derer man das Object ertstellt hat, wieder freigeben. Mit dem Parent den man setzt hat das eigentlich nichts zu tun.

DeddyH 14. Feb 2020 13:35

AW: Zur Laufzeit Comboboxen hinzufügen
 
Aus der Vcl.Controls.pas (Destruktor von TWinControl):
Zitat:

Delphi-Quellcode:
  I := ControlCount;
  while I <> 0 do
  begin
    Instance := Controls[I - 1];
    Remove(Instance);
    Instance.Destroy;
    I := ControlCount;
  end;

Besser erst nachsehen, bevor man Behauptungen aufstellt. Ich hatte mir vor Jahren mal die Mühe gemacht, seit wann das so ist, und konnte ähnlichen Code bereits in Delphi 6 finden, ältere Versionen hatte ich nicht untersucht.

himitsu 14. Feb 2020 13:37

AW: Zur Laufzeit Comboboxen hinzufügen
 
Zitat:

Zitat von Rolf Frei (Beitrag 1457523)
Seit wann ist der Parent für die Freigbae zuständig?! Das wird über den Owner gesteuert und nicht über den Parent

Leider schon immer. Ich war auch geschockt, beim Versuch zur Laufzeit eine Komponente zeitweise auf eine andere Form zu verschieben. (muß man erst den Parent abhängen und dann die Form freigeben)

Der Schuldige:
Delphi-Quellcode:
destructor TWinControl.Destroy;
begin
  ...
  I := ControlCount;
  while I <> 0 do
  begin
    Instance := Controls[I - 1];
    Remove(Instance);
    Instance.Destroy; <<<<<
    I := ControlCount;
  end;
  ...
end;
.Controls für Parent und .Components bei Owner

Logisch ist es ein reiner Fail, aber ich vermute es ist als Kackfix gedacht, für zur Laufzeit erstellte Komponenten, wo die Entwickler zu doof sind den Owner anzugeben. :freak:
Ich hätte lieber das Speicherleck, als unverständlich verschwindende Komponenten.

mkinzler 14. Feb 2020 13:42

AW: Zur Laufzeit Comboboxen hinzufügen
 
TWinControl kapselt ein Control der Win32-API. Diese kennen keinen Owner, sondern nur eine Parent, der für beides zuständig ist.

himitsu 14. Feb 2020 13:51

AW: Zur Laufzeit Comboboxen hinzufügen
 
TWinControl ist aber nicht unbedingt an die Lebensdauer des eingebetten Controls gekoppelt.
Der Innere kann sogar zwischendurch mal verschwinden und wird neu erstellt. (drum halten die Delphi-Controls auch alle Daten doppelt)
Stell mal bei einer Form das StayOnTop um und erlebe, wie das Fenster und sein Inhalt freigebeben und neu erstellt wird ... drum darf man sowas wie z.B. eigene Registrierungen für Drag&Drop nicht im Constructor machen, sondern besser in CreateWnd bzw. CreateWindowHandle.
Ich sehe da keinen Grund, dieses Verhalten daher im Delphi nachbauen zu müssen, wo es dort ja schließlich den Owner gibt.

TurboMagic 14. Feb 2020 17:53

AW: Zur Laufzeit Comboboxen hinzufügen
 
Zitat:

Zitat von Luckie (Beitrag 1457492)
Man sollte aber noch den Parent setzen, damit sie auch gezeichnet wird und den Owner, damit der Owner das Zerstören übernimmt.

Hast du dir das erste Codebeispiel mal angeschaut?
Das wird dort beides gesetz. Einmal per COnstructor und dann noch separat
der Parent per Zuweisung.

Das einzige was einen stören könnte wäre, dass der COde als Prozedur und nicht als Methode umgesetzt ist.

Luckie 14. Feb 2020 18:37

AW: Zur Laufzeit Comboboxen hinzufügen
 
Das hat er nach meinem Hinweis nachträglich eingefügt.

Vergleiche:
Timestamp seines Beitrages
Timestamp meines Beitrages
Timestamp seines Änderung

Und er hat den Änderungsgrund sogar genannt.

TurboMagic 15. Feb 2020 11:18

AW: Zur Laufzeit Comboboxen hinzufügen
 
Zitat:

Zitat von KomischerKautz (Beitrag 1457511)
Super! Das funktioniert einwandfrei. Vielen Dank für euere Hilfe!
Nun abschließend noch; den Inhalt von Comboboxen fülle ich ja normalerweise in der StringList der Combobox in den Properties. Das funktioniert hier wie es scheint nicht, da ja noch keine Combobox vorhanden ist, welche ich füllen kann.
Wie kann ich nun den Inhalt aller erzeugter Comboboxen vorbestimmen?

Wie schon geschrieben über die Items:

Combo.Items.Add('erster Eintrag');
Combo.Items.Add('zweiter Eintrag');
Combo.ItemIndex := 1; // Vorselektion 2. Eintrag, falls gewünscht

KodeZwerg 15. Feb 2020 13:33

AW: Zur Laufzeit Comboboxen hinzufügen
 
Ein neuer Versuch mit ein paar Zugaben, schönes Wochenende und diesmal wurden meinerseits auch Mängel berücksichtigt.

Viel Spass beim rumtesten.

Die .pas Datei:
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    cbPnl: TPanel;
    mainPnl: TPanel;
    infoPnl: TPanel;
    addBtn: TButton;
    procedure addBtnClick(Sender: TObject);
  private
  public
    // manuell eingefügte events die ich später verwende
    procedure cbChange(Sender: TObject);
    procedure cbClick(Sender: TObject);
  end;

var
  Form1: TForm1;
  cbList: TList;

const
  minHeight = 120;

implementation

{$R *.dfm}

procedure TForm1.addBtnClick(Sender: TObject);
var
  cb : TComboBox;
begin
  // hier wird eine neue combobox erstellt mit ein paar grundeinstellungen
  // in diesem fall erstelle ich die cb in ein panel
  cb := TComboBox.Create(cbPnl);
  cb.Parent := Self;
  cb.Left := 3;
  cb.Top := cbList.Count * cb.Height + 3;
  cb.Style := csDropDownList;
  // damit man auch was zu sehen/klicken hat, ein paar einträge erzeugen
  cb.Items.Add('CB #' + IntToStr(cbList.Count));
  cb.Items.Add('Cool #' + IntToStr(cbList.Count));
  cb.ItemIndex := 0;
  // hier weise ich der cb events zu, für weitere events einfach diesem beispiel folgen
  cb.OnChange := cbChange;
  cb.OnClick := cbClick;
  // verwaltung der cb's
  cbList.Add(cb);
  // prototyp einer dynamischen formular größe
  if ((cbList.Count + 2) * cb.Height + 3) > minHeight then
    Height := (cbList.Count + 2) * cb.Height + 3;
end;

procedure TForm1.cbChange(Sender: TObject);
begin
  infoPnl.Caption := TComboBox(Sender).Text;
end;

procedure TForm1.cbClick(Sender: TObject);
begin
  infoPnl.Caption := TComboBox(Sender).Text;
end;

initialization
  cbList := TList.Create;

finalization
  cbList.Free;

end.
die .dfm Datei:
Delphi-Quellcode:
object Form1: TForm1
  Left = 192
  Top = 125
  BorderIcons = [biSystemMenu]
  BorderStyle = bsSingle
  Caption = 'DynCbDemo by KodeZwerg'
  ClientHeight = 81
  ClientWidth = 315
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  Position = poScreenCenter
  PixelsPerInch = 96
  TextHeight = 13
  object cbPnl: TPanel
    Left = 0
    Top = 0
    Width = 150
    Height = 81
    Align = alLeft
    TabOrder = 0
  end
  object mainPnl: TPanel
    Left = 150
    Top = 0
    Width = 165
    Height = 81
    Align = alClient
    TabOrder = 1
    object infoPnl: TPanel
      Left = 1
      Top = 1
      Width = 163
      Height = 41
      Align = alTop
      BevelOuter = bvNone
      Caption = 'CB Item Display'
      TabOrder = 0
    end
    object addBtn: TButton
      Left = 16
      Top = 48
      Width = 129
      Height = 25
      Caption = 'Add ComboBox'
      TabOrder = 1
      OnClick = addBtnClick
    end
  end
end

Luckie 15. Feb 2020 15:19

AW: Zur Laufzeit Comboboxen hinzufügen
 
Jetzt noch das Erstellen in eine separate Methode aufrufen, die von der Schaltfläche aufgerufen wird mit der Position usw. als Parameter und man kann den Code universell einsetzten.

DeddyH 15. Feb 2020 15:56

AW: Zur Laufzeit Comboboxen hinzufügen
 
Dann aber bitte die Liste noch als Feld es Formulars deklarieren, in dessen FormCreate erzeugen und im FormDestroy wieder freigeben, sonst bekommt man ganz schnell Kummer, wenn das Formular dynamisch erzeugt und freigegeben wird.

Luckie 15. Feb 2020 16:11

AW: Zur Laufzeit Comboboxen hinzufügen
 
Das gehört eigentlich nicht mehr dazu. Vielleicht will ja jemand die Comboboxen anders verwalten. In einem statischen Array oder in einer Objektliste oder...Aber das ist der Basiscode, den man auf alle Fälle benötigt.

KodeZwerg 17. Feb 2020 07:27

AW: Zur Laufzeit Comboboxen hinzufügen
 
Zitat:

Zitat von KodeZwerg (Beitrag 1457597)
Delphi-Quellcode:
  cb := TComboBox.Create(cbPnl);
  cb.Parent := Self;

Sollte genau andersrum sein, Wein und Delphi verträgt sich nicht :-)
Also
Delphi-Quellcode:
  cb := TComboBox.Create(Self);
  cb.Parent := cbPnl;
Self steht in diesem Fall für's aktuelle Formular, wenn man den Schnippsel als methode verfrachtet sollte "Self" mit 'nem Formular-Bezeichner ausgetauscht werden und als Parent halt ein Control oder Formular angeben.

Joar, die cbList in Formular Klasse mit rein, das macht Sinn, mein Fehler! (keine Ironie)

Ich hätte gerne noch 'ne mini Erklärung warum Liste.Create/.Free eher in FormCreate/Destroy rein sollte.
initialization/finalization ist doch eigentlich 'ne super stelle dafür, finde ich.

haentschman 17. Feb 2020 07:37

AW: Zur Laufzeit Comboboxen hinzufügen
 
Zitat:

cbList in Formular Klasse mit rein, das macht Sinn
Zitat:

warum Liste.Create/.Free eher in FormCreate/Destroy rein sollte
...deswegen. :zwinker:

DeddyH 17. Feb 2020 07:39

AW: Zur Laufzeit Comboboxen hinzufügen
 
Wenn das Formular und die Liste unterschiedliche Lebenszyklen haben, dann hat man recht schnell tote Referenzen in der Liste. Sobald der Parent/Owner der ComboBoxen freigegeben wird, gibt dieser auch die ComboBoxen frei. Diese stehen aber weiterhin in der Liste. Da macht es doch eher Sinn, die Lebenszyklen der Liste und des Formulars anzugleichen, außerdem braucht man dann auch keine globale Variable mehr.

KodeZwerg 17. Feb 2020 07:45

AW: Zur Laufzeit Comboboxen hinzufügen
 
Super erläuterung und klar Formular Feld an Lebensdauer des Formulars binden macht Sinn.
Danke Euch!

himitsu 17. Feb 2020 12:08

AW: Zur Laufzeit Comboboxen hinzufügen
 
Eine TComponentList könnte man auch verwenden.
Wird eine Komponente (TComponent) freigegeben, dann wird sie autoamtisch aus der Liste entfernt.

TComponent haben ein Notify-System, um sich gegenseitig über ihre Freigabe zu informieren, z.B. Property auf nil zu setzen oder sich aus den Listen der Components und Controls ihrer Parents zu entfernen.

Und in den NextGen-Compilern (Android, iOS) gibt es Weak-Referenzen, die werden automatisch auf nil gesetzt, wenn man die Komponente freigibt.

KodeZwerg 17. Feb 2020 14:39

AW: Zur Laufzeit Comboboxen hinzufügen
 
Zitat:

Zitat von Luckie (Beitrag 1457602)
...in eine separate Methode aufrufen...

da hab ich mir auch shon ein paar gedanken gemacht aber weiß momentan noch nicht so genau wie man es am elegantesten löst.
ich würde mir eine separate unit erzeugen mit einer type dynCreate = record deklaration und darin funktionen wie "ComboBox" definieren, aber wie ich die verschiedensten möglichkeiten einer verwaltung implementiere, da bin ich ratlos.
für den TE sollte das bereits vorhandene ausreichen denk ich mal.

jus 18. Feb 2020 10:58

AW: Zur Laufzeit Comboboxen hinzufügen
 
Zitat:

Zitat von himitsu (Beitrag 1457686)
Eine TComponentList könnte man auch verwenden.
Wird eine Komponente (TComponent) freigegeben, dann wird sie autoamtisch aus der Liste entfernt.

TComponent haben ein Notify-System, um sich gegenseitig über ihre Freigabe zu informieren, z.B. Property auf nil zu setzen oder sich aus den Listen der Components und Controls ihrer Parents zu entfernen.
.....

Wie könnte so ein Notify-System aussehen? Ich bin schon paar paar Mal in fremde Sourcen darüber gestolpert, aber so richtig kapiert habe das nicht. Ich wäre sehr interesiert wie man das mit einer Liste mit Notify realisiert :-D

Dennis07 18. Feb 2020 11:02

AW: Zur Laufzeit Comboboxen hinzufügen
 
Jede Komponente hat FreeNotifications, die sie u.a. an diejenigen Komponenten versendet, die sie als Besitzer festgelegt haben.
Wenn eine Komponente zerstört wird, werden deren Subkomponenten, die in einer (eigentlich zwei) Komponentenlisten gespeichert sind, automatisch freigegeben. Nicht zu verwechseln ist dies mit den eingebetteten Steuerelementen, die in TList<TControl> gespeichert werden; diese haben nichts damit zu tun.

himitsu 18. Feb 2020 11:34

AW: Zur Laufzeit Comboboxen hinzufügen
 
siehe TComponentList (unit Contnrs)

Eine TList, die ein Dummy-TComponent drinnen hat oder die selbst ein TComponent ist, über dessen TComponent.Notification beim opRemove es das jeweilige Objekt aus der Liste löscht.
TList.Notify bei lnAdded via TComponent.FreeNotification registrieren und beim lnExtracted/lnDeleted via TComponent.RemoveFreeNotification deregistrieren. (wer bei wem ist egal, da alles gegenseitig)

Delphi-Quellcode:
procedure TComponentListDummy.Notification(AComponent: TComponent; Operation: TOperation);
begin
  if Operation = opRemove then
    Parent.Extract(AComponent); // Item aus Liste entfernen, ohne enthaltenes Objekt (nochmal) freizugeben
  inherited;
end;

procedure TComponentList.Notify(Ptr: Pointer; Action: TListNotification);
begin
  if Assinged(Ptr) then
    case Action of
      lnAdded:
        TComponent(Ptr).FreeNotification(FDummy);
      lnExtracted, lnDeleted:
        TComponent(Ptr).RemoveFreeNotification(FDummy);
    end;
  inherited;
end;
Nochmal als Beispiel mit einem Property:
Delphi-Quellcode:
type
  TDemo = class(TComponent)
  private
    FLink: TComponent;
    procedure SetLink(Value: TComponent);
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  public
    property Link: TComponent read FLink write SetLink;
  end;

procedure TDemo.SetLink(Value: TComponent);
begin
  if Assigned(FLink) then
    Self.RemoveFreeNotification(FLink); // oder FLink.RemoveFreeNotification(Self);
  FLink := Value;
  if Assigned(FLink) then
    Self.FreeNotification(FLink);
end;

procedure TDemo.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited;
  if Operation = opRemove then begin
    if FLink = AComponent then
      FLink := nil;
  end;
end;

jus 20. Feb 2020 18:28

AW: Zur Laufzeit Comboboxen hinzufügen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von himitsu (Beitrag 1457779)
siehe TComponentList (unit Contnrs)
...
Delphi-Quellcode:
procedure TComponentListDummy.Notification(AComponent: TComponent; Operation: TOperation);
begin
  if Operation = opRemove then
    Parent.Extract(AComponent); // Item aus Liste entfernen, ohne enthaltenes Objekt (nochmal) freizugeben
  inherited;
end;

procedure TComponentList.Notify(Ptr: Pointer; Action: TListNotification);
begin
  if Assinged(Ptr) then
    case Action of
      lnAdded:
        TComponent(Ptr).FreeNotification(FDummy);
      lnExtracted, lnDeleted:
        TComponent(Ptr).RemoveFreeNotification(FDummy);
    end;
  inherited;
end;
....

@himitsu: vielen Dank für die Erklärung! Hat bei mir eine Weile gedauert, bis ich verstanden habe, dass dein Code nur zur Erklärung dient und bereits implizit im TComponentList enthalten ist. :oops: Sprich, man muß sich normalerweise bei TComponentList nicht mehr um das Entfernen aus der TComponentList kümmern, wenn eine Komponente freigegeben wird.

Vielleicht auch für den TE oder andere interessant, aufbauend auf den Beitrag #8 von KodeZwerg ein Beispiel mit TComponentList:
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Contnrs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private-Deklarationen }
    ComponentList: TComponentList;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  cb: TComboBox;
begin
  cb := TComboBox.Create(self);
  cb.Parent := self;
  cb.Top := (ComponentList.Count * (cb.Height + 3));
  // weitere eigenschaften setzen
  cb.Items.Add(DateTimeToStr(now));  // mit irgendein Text blabla Text füllen
  cb.ItemIndex := 0;
  ComponentList.Add(cb);
  Caption := 'ComponentList: ' + IntToStr(ComponentList.Count);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  cb: TComboBox;
begin
  if ComponentList.Count > 0 then
  begin
    cb := TComboBox(ComponentList[ComponentList.Count-1]);
    cb.Free;
    Caption := 'ComponentList: ' + IntToStr(ComponentList.Count);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ComponentList := TComponentList.Create;
  Caption := 'ComponentList: ' + IntToStr(ComponentList.Count);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  ComponentList.Free;
end;

end.

KodeZwerg 21. Feb 2020 07:24

AW: Zur Laufzeit Comboboxen hinzufügen
 
Danke an himitsu und jus für den Component-Notify tipp/Beispiel-Code, ich werde übers Wochenende mal 'ne kleine DynamicControls unit erschaffen :-)


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:44 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