Was ich versuche, in vereinfachter Form zu erreichen, besteht darin, eine Liste dynamisch erstellter Schaltflächen zu erstellen. Wenn Sie auf einen der Knöpfe klicken, sollte er aus der Liste entfernt werden und sein Objekt sollte freigegeben werden. Mein Ansatz ist:Freigeben von Schaltflächen in einer Liste in OnClick
- erstellen
TList<TButton>
- Erstellen Sie ein paar
TButton
Objekte und fügen sie demTList<TButton>
- Weisen Sie die
Form
alsParent
für jede der erstelltenTButton
Objekte - Vergeben Sie einen
Position
Für jedes der erstelltenTButton
Objekte - Weisen Sie eine
OnClick
Handler-Methode zu jedem der CreTButton
ated Objekte - Der
OnClick
Handler setzt dieSender
TButton
‚sParent
-nil
und löscht sie aus demTList<TButton>
, so dass ARC dasTButton
Objekt befreien können, die auf angeklickt wurde.
Wenn ich auf eine der dynamisch erstellten Schaltflächen klicke, bekomme ich einen "Segmentation Fault". Ich vermute, dass es ist, weil ich das TButton
Objekt in seinem eigenen OnClick
Handler befreie und die Klasse versucht, einige andere Sachen damit nach meinem Handler zu machen.
Ich habe dies auf Android getestet. Ich gehe davon aus, dass das auch auf iOS oder einer anderen ARC-Plattform passieren wird.
Gibt es einen besseren/richtigen Weg, dies zu tun, oder einen anderen Ansatz, dem ich folgen sollte, damit es so funktioniert, wie ich es möchte?
Hier ist ein Beispielcode. Es ist für ein Formular mit einem Design-Time-Button (Button1
) darauf. Durch wiederholtes Klicken auf diese Schaltfläche werden neue Schaltflächen dynamisch erstellt und zur Liste hinzugefügt.
unit Unit2;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
FMX.Controls.Presentation, FMX.StdCtrls, System.Generics.Collections;
type
TForm2 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
ButtonList : TList<TButton>;
procedure ButtonClick(Sender: TObject);
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.fmx}
procedure TForm2.ButtonClick(Sender: TObject);
var
pos : Integer;
begin
pos := ButtonList.IndexOf(TButton(Sender));
TButton(Sender).Parent := nil;
ButtonList.Delete(pos);
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
ButtonList := TList<TButton>.Create;
end;
procedure TForm2.Button1Click(Sender: TObject);
var
pos : Integer;
begin
pos := ButtonList.Add(TButton.Create(nil));
ButtonList.Items[pos].Parent := Form2;
ButtonList.Items[pos].Position.Y := 50 * ButtonList.Count;
ButtonList.Items[pos].OnClick := ButtonClick;
end;
end.
Vielen Dank Remy. Ihr erster Ansatz, 'TThread.Queue' in' TThread.CreateAnonymousThread' zu verwenden, funktionierte perfekt und ich bevorzugte diesen Ansatz bei der Verwendung eines 'TTimer'. Ich musste jedoch einen Aufruf von "Start()" hinzufügen, da AnonymousThread in einem Suspended-Zustand erstellt wurde. –
Ich habe eine Frage über Ihre Verwendung von 'DisposedOf()' obwohl. Was ich stattdessen tue, ist, das 'Elternteil' des 'TButton'-Objekts auf' Null 'zu setzen. Wie ich verstehe, dekrementiert dies den "RefCount" in diesem Fall auf 1 und sobald das Objekt dann den Gültigkeitsbereich verlässt, zerstört ARC das Objekt und gibt den Speicher frei. Nach meinem Verständnis zerstört 'DisposedOf()' das Objekt, indem es den Destruktor aufruft, lässt aber immer noch den Speicher frei für ARC, was nur passiert, wenn 'RefCount' Null erreicht. Gibt es einen bestimmten Grund, warum Sie stattdessen "DisposedOf()" gewählt haben? –
@EdreanErnst es macht den Code klarer, was seine Absicht ist. Der Destruktor wird die "Parent" -Referenz trotzdem entfernen und den Refcount dekrementieren. –