Erstellen von Komponenten zur Laufzeit - Delphi
-
05-07-2019 - |
Frage
Wie kann ich eine Komponente zur Laufzeit und dann mit ihr arbeiten zu erstellen (Ändern von Eigenschaften, etc.)?
Lösung
Es hängt davon ab, ob es sich um eine visuelle oder nicht-visuelle Komponente ist. 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. Aber Sie haben 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 Erläuterungen zu dem obigen Code:
- Durch den Eigentümer der Komponente Einstellung (die Parameter des Konstruktors) die Komponente zerstört wird, wenn die besitzende Form zerstört wird.
- die
Parent
Eigenschaft Einstellung macht die Komponente sichtbar. Wenn Sie es Ihre Komponente vergessen werden nicht angezeigt. (Es ist einfach, dass man verpassen :))
Wenn Sie viele Komponenten Sie können das gleiche tun wie oben, aber in einer Schleife:
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;
Dies wird 10 Tasten am linken Rand des Formulars hinzufügen. Wenn Sie die Tasten später ändern möchten, können Sie diese 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 Event-Handler zuweisen:
Sie haben eine Event-Handler-Methode erstellen und an die Ereigniseigenschaft zuweisen.
procedure TForm1.MyButtonClick(Sender: TObject);
var
Button: TButton;
begin
Button := Sender as TButton;
ShowMessage(Button.Caption + ' clicked');
end;
B := TButton.Create;
//...
B.OnClick := MyButtonClick;
Andere Tipps
, um die Laufzeitkomponente Erstellungsprozess zu vereinfachen, können Sie GExperts .
- Erstellen Sie eine Komponente (oder mehr Komponenten) visuell und legen Sie seine Eigenschaften.
- Wählen Sie eine oder mehrere Komponenten und führen GExperts, Komponenten zu-Code.
- Fügen Sie den erzeugten Code in Ihre Anwendung.
- Entfernen Komponente (n) aus der visuellen Form Designer.
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;
Ich möchte nur hinzufügen, dass, wenn Steuerelemente dynamisch das Hinzufügen ... es als eine gute Idee, sie zu einer Objektliste (TObjectList) wie vorgeschlagen in <1> durch @Despatcher 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. D.h System.Contnrs.pas die Basis Container Einheit Und Sie können viele Objektlisten haben. Ich schlage vor, mit einer TObjectList für jede Art von Kontrolle, die 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
So können Sie leicht manipulieren / verwalten jede Kontrolle, wie Sie wissen, welche Art der Steuerung ist es 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 auf die Methoden und Eigenschaften dieser Kontrolle verwenden Vergessen Sie nicht die TObjectLists zu schaffen, vielleicht in Form erstellen Ereignis ...
checkBoxCntrlsList := TObjectList.Create;
comboboxCntrlsList := TObjectList.Create;
Aber wenn ich weiß nicht sicher, wie viele Komponenten I erstellen möchten, zum Beispiel wenn es hängt von Benutzer-Entscheidung. Wie kann ich also Komponenten dynamisch deklarieren?
Die Antwort wird vorgeschlagen - der einfachste Weg, eine Liste von Objekten (Komponenten) ist. TObjectList ist die einfachste (in Einheit contnrs) zu verwenden. Listen sind groß!
In Form1 Public
MyList: TObjectList;
procedure AnyButtonClick(Sender: TObject);
// Sie können anspruchsvollere bekommen und // TNotifyevents erklären und sie zuweisen, aber es einfach halten :) lassen . . .
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;
kann eine Objektliste enthalten ein beliebiges 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 commenters kann ich der Kürze wegen zu stark vereinfachte, aber ich hoffe, dass Sie ge die Idee. Sie benötigen einen Mechanismus, um die Objekte zu verwalten, sobald sie erstellt werden und Listen sind für dieses Material ausgezeichnet.
Während eines Forschungs auf „die Schaffung eines delphi Form XML-basierte Vorlage“, finde ich etwas Nützliches Aufzeigen RTTI und Verwendung von offenen Tools api (ToolsApi.pas glaube ich). Werfen Sie einen Blick auf die Schnittstellen im Gerät.
Sehr erleichtern. Rufen Sie erstellen. Beispiel:
procedure test
var
b : TButton;
begin
b:=TButton.Create(nil);
b.visible:=false;
end;
Dies erzeugt eine Komponente (TButton ist eine Komponente) zur Laufzeit und setzt die Eigenschaft sichtbar.
Für den Konstruktor: pass null, wenn Sie den Speicher selbst zu verwalten. Übergeben Sie einen Zeiger eine andere Komponente, wenn Sie haben wollen, es zerstört, wenn die andere Komponente zerstört.
Einige Komponenten überschreiben die ‚Loaded‘ -Methode. Diese Methode wird nicht automatisch aufgerufen werden, wenn Sie eine Instanz zur Laufzeit erstellen. Es wird von Delphi aufgerufen werden, wenn aus der Formulardatei (DFM) Laden abgeschlossen ist.
Wenn die Methode Initialisierungscode enthält, kann Ihre Anwendung unerwartetes Verhalten zeigen, wenn zur Laufzeit erstellt. In diesem Fall überprüfen, ob die Komponente Schreiber diese Methode verwendet hat.
Wenn Sie nisten Kontrollen in Gruppe Boxen gewinnen / Seite Steuerelemente / Etc ..., ich denke, dass es von Vorteil ist, die übergeordnete Gruppe Box auch der Eigentümer sein zu haben. Ich habe einen starken Rückgang der Fenster schließen mal bemerkt, wenn dies zu tun, im Gegensatz zu, das der Eigentümer immer die wichtigste Form sein.
Dies ist Beispiel dafür, wie Ohrenmarke auf Evernote zu emulieren
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.