Wie kann ich zur Laufzeit eine Komponente erstellen und dann damit arbeiten (Eigenschaften ändern usw.)?Komponenten zur Laufzeit erstellen - Delphi
Antwort
Es hängt davon ab, ob es sich um eine visuelle oder nicht-visuelle Komponente handelt. Das Prinzip ist das gleiche, aber es gibt einige zusätzliche Überlegungen für jede Art von Komponente.
Für nicht-visuelle Komponenten
var
C: TMyComponent;
begin
C := TMyComponent.Create(nil);
try
C.MyProperty := MyValue;
//...
finally
C.Free;
end;
end;
Zur visuellen Komponenten:
Im Wesentlichen visuelle Komponenten sind in der gleichen Art und Weise wie nicht-visuelle Komponenten erstellt. Sie müssen jedoch einige zusätzliche Eigenschaften festlegen, um sie sichtbar zu machen.
var
C: TMyVisualComponent;
begin
C := TMyVisualComponent.Create(Self);
C.Left := 100;
C.Top := 100;
C.Width := 400;
C.Height := 300;
C.Visible := True;
C.Parent := Self; //Any container: form, panel, ...
C.MyProperty := MyValue,
//...
end;
Einige Erklärungen zum Code oben:
- zerstört wird, die Eigentümer der Komponente (die Parameter des Konstruktors) die Komponente Durch die Einstellung, wenn die besitzende Form zerstört wird.
- Durch Einstellen der
Parent
-Eigenschaft wird die Komponente sichtbar. Wenn Sie es vergessen, wird Ihre Komponente nicht angezeigt. (Es ist einfach, dass man :) missen)
Wenn Sie viele Komponenten wollen Sie das gleiche wie oben, aber in einer Schleife tun können:
var
B: TButton;
i: Integer;
begin
for i := 0 to 9 do
begin
B := TButton.Create(Self);
B.Caption := Format('Button %d', [i]);
B.Parent := Self;
B.Height := 23;
B.Width := 100;
B.Left := 10;
B.Top := 10 + i * 25;
end;
end;
Diese 10 Tasten auf der linken Seite hinzufügen wird Grenze des Formulars. Wenn Sie die Schaltflächen später ändern möchten, können Sie sie in einer Liste speichern. (TComponentList ist am besten geeignet, sondern nehmen auch einen Blick auf die Vorschläge aus den Kommentaren zu dieser Antwort)
Wie Ereignishandler zuweisen:
Sie haben eine Event-Handler-Methode erstellen und weisen es die Ereigniseigenschaft.
procedure TForm1.MyButtonClick(Sender: TObject);
var
Button: TButton;
begin
Button := Sender as TButton;
ShowMessage(Button.Caption + ' clicked');
end;
B := TButton.Create;
//...
B.OnClick := MyButtonClick;
Sehr einfach. Rufen Sie Erstellen auf. Beispiel:
Dies erstellt eine Komponente (TButton ist eine Komponente) zur Laufzeit und legt die Eigenschaft sichtbar.
Für den Konstruktor: pass nil, wenn Sie den Speicher selbst verwalten möchten. Übergeben Sie einen Zeiger an eine andere Komponente, wenn Sie ihn zerstören möchten, wenn die andere Komponente zerstört wird.
Es ist notwendig, den Zeiger auf den Besitzer des Elements zu übergeben. TButton.Create (Besitzer); –
Dieser Code wird nicht kompiliert –
> Notwendigkeit für Besitzer Nicht unbedingt. TButton.Create (Null); ist ein gültiger Code. aber Sie müssen es jetzt explizit zerstören. Das Erstellen von visuellen Komponenten mit einem Null-Besitzer ist manchmal nützlich. – Despatcher
Um die Erstellung der Laufzeitkomponente zu vereinfachen, können Sie GExperts verwenden.
- Erstellen Sie eine Komponente (oder mehrere Komponenten) visuell und legen Sie ihre Eigenschaften fest.
- Wählen Sie eine oder mehrere Komponenten aus und führen Sie GExperts, Components to Code aus.
- Fügen Sie den generierten Code in Ihre Anwendung ein.
- Komponente (n) aus dem visuellen Formular-Designer entfernen.
Beispiel (TButton-Erstellungscode auf diese Weise generiert):
var
btnTest: TButton;
btnTest := TButton.Create(Self);
with btnTest do
begin
Name := 'btnTest';
Parent := Self;
Left := 272;
Top := 120;
Width := 161;
Height := 41;
Caption := 'Component creation test';
Default := True;
ParentFont := False;
TabOrder := 0;
end;
Toller Tipp! Genau das hätte ich vorgeschlagen. GExperts ist ein großartiges Tool für die Verwendung mit Delphi. –
... oder Sie können es im visuellen Editor entwerfen und dann einen Blick in die .dfm-Datei werfen. Grundsätzlich ist genau das Gleiche im Text – Earlz
Gracias. Ich ziehe es vor, alle Dinge selbst zu schreiben (ich weiß, dass das Rad vielleicht neu erfunden wird, aber ich habe mehr Kontrolle darüber), trotzdem scheint es, dass das GExpert-Tool keinen reinen Code ändert und das klingt gut. Danke nochmal für die Beratung. – QMaster
Aber wenn ich weiß nicht sicher, wie viele Komponenten I erstellen möchten, zum Beispiel wenn es von der Entscheidung des Benutzers abhängt. Wie kann ich Komponenten dynamisch deklarieren?
Die Antwort wurde vorgeschlagen - der einfachste Weg ist eine Liste von Objekten (Komponenten). TObjectList ist am einfachsten zu verwenden (in Einheiten). Listen sind großartig!
In Form1 Public
MyList: TObjectList;
procedure AnyButtonClick(Sender: TObject);
// Sie können anspruchsvollere bekommen und // TNotifyevents erklären und ihnen zuweisen, sondern lässt es einfach halten :) . . .
procedure Tform1.AnyButtonClick(Sender: TObject);
begin
If Sender is TButton then
begin
Case Tbutton(Sender).Tag of
.
.
.
// Or You can use the index in the list or some other property
// you have to decide what to do
// Or similar :)
end;
end;
procedure TForm1.BtnAddComponent(Sender: TObJect)
var
AButton: TButton;
begin
AButton := TButton.Create(self);
Abutton. Parent := [Self], [Panel1] [AnOther Visual Control];
AButton.OnClick := AnyButtonClick;
// Set Height and width and caption ect.
.
.
.
AButton.Tag := MyList.Add(AButton);
end;
Eine Objektliste kann eine beliebige Objekt visuelle oder nicht, aber das gibt Ihnen einen zusätzlichen Aufwand für Aussortieren, welche Elemente sind, die - besser bezogene Listen haben, wenn Sie mehrere dynamische Steuerelemente auf ähnliche Platten zum Beispiel wollen.
Hinweis: Wie andere Kommentatoren habe ich vielleicht kurz verkürzt, aber ich hoffe, Sie haben die Idee. Sie benötigen einen Mechanismus, um die Objekte zu verwalten, sobald sie erstellt sind und Listen sind hervorragend für diese Dinge.
Einige Komponenten haben Vorrang vor der Loaded-Methode. Diese Methode wird nicht automatisch aufgerufen, wenn Sie eine Instanz zur Laufzeit erstellen. Es wird von Delphi aufgerufen, wenn das Laden aus der Formulardatei (DFM) abgeschlossen ist.
Wenn die Methode Initialisierungscode enthält, zeigt Ihre Anwendung möglicherweise ein unerwartetes Verhalten, wenn sie zur Laufzeit erstellt wird. Überprüfen Sie in diesem Fall, ob der Komponentenschreiber diese Methode verwendet hat.
Wenn Sie win-Steuerelemente in Gruppenrahmen/Seitensteuerelemente/Etc ... verschachteln, ist es meiner Meinung nach vorteilhaft, wenn die Gruppe der übergeordneten Gruppen auch der Eigentümer sein soll. Ich habe eine starke Abnahme der Schließzeiten von Fenstern bemerkt, wenn ich dies tue, im Gegensatz dazu, dass der Besitzer immer die Hauptform sein muss.
Während einer Forschung über "Erstellen eines Delphi-Formulars mit XML-basierte Vorlage", finde ich etwas nützlich, RTTI und die Verwendung von Open Tools API (ToolsApi.pas denke ich). Sehen Sie sich die Schnittstellen in der Einheit an.
Ich möchte nur hinzufügen, dass beim dynamischen Hinzufügen von Steuerelementen ... es eine gute Idee, sie zu einer Objektliste (TObjectList) wie in < 1> von @Despatcher vorgeschlagen hinzuzufügen.
procedure Tform1.AnyButtonClick(Sender: TObject);
begin
If Sender is TButton then
begin
Case Tbutton(Sender).Tag of
.
.
.
// Or You can use the index in the list or some other property
// you have to decide what to do
// Or similar :)
end;
end;
procedure TForm1.BtnAddComponent(Sender: TObJect)
var
AButton: TButton;
begin
AButton := TButton.Create(self);
Abutton. Parent := [Self], [Panel1] [AnOther Visual Control];
AButton.OnClick := AnyButtonClick;
// Set Height and width and caption ect.
.
.
.
AButton.Tag := MyList.Add(AButton);
end;
Sie müssen die Einheit 'Contnrs' zu Ihrer uses-Liste hinzuzufügen. Ie System.Contnrs.pas die Basis Container Unit Und Sie können viele Objektlisten haben. Ich empfehle die Verwendung einer TObjectList für jede Art von Steuerelement, das Sie verwenden z.
Interface
Uses Contnrs;
Type
TMyForm = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
Var
MyForm: TMyForm;
checkBoxCntrlsList: TObjectList; //a list for the checkBoxes I will createin a TPanel
comboboxCntrlsList: TObjectList; //a list of comboBoxes that I will create in some Form Container
Dies ermöglicht es Ihnen, jedes Steuerelement leicht zu manipulieren/verwalten, wie Sie wissen, welche Art von Steuerelement es ist, z.
Var comboBox: TComboBox;
I: Integer;
begin
For I = 0 to comboboxCntrlsList.Count -1 do // or however you like to identify the control you are accessing such as using the tag property as @Despatcher said
Begin
comboBox := comboboxCntrlsList.Items[I] as TComboBox;
...... your code here
End;
end;
Auf diese Weise können Sie dann die Methoden und Eigenschaften dieser Kontrolle Vergessen Sie nicht die TObjectLists erstellen können, vielleicht in Form Ereignis erstellen ...
checkBoxCntrlsList := TObjectList.Create;
comboboxCntrlsList := TObjectList.Create;
Dieses Beispiel ist So emulieren Sie den Button Tag auf Evernote
unit Unit7;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, CHButton, Vcl.ExtCtrls, RzPanel, CHPanel, RzCommon,RzBmpBtn, Vcl.StdCtrls;
type
// This is panel Button
TButtonClose = class (TRzPanel)
CloseButton : TRzBmpButton;
procedure CloseButtonClick(Sender: TObject);
procedure CloseButtonMouseEnter(Sender: TObject);
procedure MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
TForm7 = class(TForm)
CHButton1: TCHButton;
RzPanel1: TRzPanel;
RzBmpButton1: TRzBmpButton;
procedure CHButton1Click(Sender: TObject);
procedure RzBmpButton1Click(Sender: TObject);
procedure RzPanel1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure RzPanel1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure RzPanel1MouseEnter(Sender: TObject);
procedure RzBmpButton1MouseEnter(Sender: TObject);
procedure FormMouseEnter(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form7: TForm7;
MyCloseButton : TButtonClose;
implementation
{$R *.dfm}
// constructor for on the fly component created
constructor TButtonClose.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
// Set Events for the component
Self.OnMouseEnter := Self.CloseButtonMouseEnter;
Self.OnMouseDown := Self.MouseDown;
Self.OnMouseUp := Self.MouseUp;
Self.Height := 25;
// Close button on top panel Button
// Inherited from Raize Bitmap Button
CloseButton := TRzBmpButton.Create(self);
// Set On Click Event for Close Button
CloseButton.OnClick := Self.CloseButtonClick;
// Place Close Button on Panel Button
CloseButton.Parent := self;
CloseButton.Left := 10;
CloseButton.Top := 5;
CloseButton.Visible := False;
// Setting the image for the button
CloseButton.Bitmaps.Up.LoadFromFile(ExtractFilePath(Application.ExeName)+'\close.bmp');
end;
procedure TButtonClose.CloseButtonClick(Sender: TObject);
begin
// Free the parent (Panel Button)
TControl(Sender).Parent.Free;
end;
procedure TButtonClose.CloseButtonMouseEnter(Sender: TObject);
begin
// Show the Close button
CloseButton.Visible := True;
end;
procedure TButtonClose.MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
// Emulate Button down state, since it is panel
TRzPanel(Sender).BorderOuter := fsLowered;
end;
procedure TButtonClose.MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
// Emulate Button up state, since it is panel
TRzPanel(Sender).BorderOuter := fsRaised;
end;
destructor TButtonClose.Destroy;
begin
inherited Destroy;
end;
procedure TForm7.FormCreate(Sender: TObject);
begin
// Create Panel Button on the fly
MyCloseButton := TButtonClose.Create(self);
MyCloseButton.Caption := 'My Button';
MyCloseButton.Left := 10;
MyCloseButton.Top := 10;
// Don't forget to place component on the form
MyCloseButton.Parent := self;
end;
procedure TForm7.FormMouseEnter(Sender: TObject);
begin
if Assigned(RzBmpButton1) then
RzBmpButton1.Visible := False;
// Hide when mouse leave the button
// Check first if myCloseButton Assigned or not before set visible property
if Assigned(MyCloseButton.CloseButton) then
MyCloseButton.CloseButton.Visible := False;
end;
procedure TForm7.RzBmpButton1Click(Sender: TObject);
begin
TControl(Sender).Parent.Free;
end;
procedure TForm7.RzBmpButton1MouseEnter(Sender: TObject);
begin
RzBmpButton1.Visible := True;
end;
procedure TForm7.RzPanel1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
TRzPanel(Sender).BorderOuter := fsLowered;
end;
procedure TForm7.RzPanel1MouseEnter(Sender: TObject);
begin
RzBmpButton1.Visible := True;
end;
procedure TForm7.RzPanel1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
TRzPanel(Sender).BorderOuter := fsRaised;
end;
procedure TForm7.CHButton1Click(Sender: TObject);
begin
FreeAndNil(Sender);
end;
end.
Aber wenn ich nicht sicher weiß, wie viele Komponenten ich erstellen möchte, z. wenn es von der Entscheidung des Benutzers abhängt. Wie kann ich Komponenten dynamisch deklarieren? –
Der Unterschied, ob nil oder eine andere Komponente als Eigentümer übergeben werden soll, hat nichts damit zu tun, ob die Komponente sichtbar ist oder nicht, nur mit der Lebensdauer des Objekts. Eine unsichtbare Komponente, die nicht in derselben Methode freigegeben wurde, kann genau wie in Ihrem zweiten Snippet erstellt und automatisch vom Eigentümer freigegeben werden. – mghie
s/visible/visual/g – mghie