Création de composants à l'exécution-Delphi
Comment puis-je créer un component à l'exécution et travailler avec (Modifier les propriétés, etc.)?
9 réponses
cela dépend s'il s'agit d'un élément visuel ou non visuel. Le principe est le même, mais il y a certaines considérations supplémentaires pour chaque type de composant.
Pour les composants non visuels
var
C: TMyComponent;
begin
C := TMyComponent.Create(nil);
try
C.MyProperty := MyValue;
//...
finally
C.Free;
end;
end;
pour les composantes visuelles:
essentiellement, les composantes visuelles sont créées de la même manière que les composantes non visuelles. Mais vous devez définir certaines propriétés supplémentaires pour les rendre visibles.
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;
quelques explications au code ci-dessus:
- en définissant le propriétaire du composant (le paramètre du constructeur) le composant est détruit lorsque la forme propriétaire est détruite.
Parent
propriété rend le composant visible. Si vous oubliez votre composant ne sera pas affiché. (Il est facile de rater celle-là :) )
Si vous voulez de nombreux composants vous pouvez faire la même chose que ci-dessus mais dans un boucle:
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;
cela ajoutera 10 boutons à la bordure gauche du formulaire. Si vous souhaitez modifier les boutons plus tard, vous pouvez les stocker dans une liste. ( TComponentList ist le mieux adapté, mais aussi de prendre un coup d'oeil sur les propositions de commentaires pour cette réponse)
comment assigner des gestionnaires d'événements:
vous devez créer une méthode de handler d'événement et l'attribuer à la propriété d'événement.
procedure TForm1.MyButtonClick(Sender: TObject);
var
Button: TButton;
begin
Button := Sender as TButton;
ShowMessage(Button.Caption + ' clicked');
end;
B := TButton.Create;
//...
B.OnClick := MyButtonClick;
pour simplifier le processus de création des composants d'exécution, vous pouvez utiliser GExperts.
- Créer un composant (ou plus) visuellement et définir ses propriétés.
- sélectionnez un ou plusieurs composants et exécutez GExperts, Components to Code.
- collez le code généré dans votre application.
- supprimer le(S) composant (s) du concepteur de la forme visuelle.
exemple (TButton-code de création généré dans ce façon):
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;
je voudrais juste ajouter que lors de l'ajout dynamique de contrôles... comme une bonne idée de les ajouter à une liste d'objets (TObjectList) comme suggéré dans <1> par @Despatcher.
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;
Vous devez ajouter l'Unité Contnrs " à votre liste des Utilisations. I. e Système.Contnrs.pas L'Unité de base Containers Et vous pouvez avoir beaucoup de listes d'objets. Je suggère d'utiliser un TObjectList pour chaque type de contrôle que vous utilisez par exemple,
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
cela vous permet de manipuler facilement/gérer chaque contrôle comme vous saurez quel type de contrôle il est par exemple
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;
Cela vous permet d'utiliser les méthodes et les propriétés de ce contrôle N'oubliez pas de créer les TObjectLists, peut-être sous la forme créer l'événement...
checkBoxCntrlsList := TObjectList.Create;
comboboxCntrlsList := TObjectList.Create;
mais si Je ne sais pas sûrement combien de composants je veux créer, par exemple si cela dépend de la décision de l'utilisateur. Alors comment puis-je déclarer des composants de façon dynamique?
la réponse a été suggérée - la façon la plus simple est une liste d'Objets(Composants). TObjectList est le plus simple à utiliser (dans les contnrs unitaires). Les listes sont très!
In Form1 Public
MyList: TObjectList;
procedure AnyButtonClick(Sender: TObject);
// Vous pouvez obtenir plus sophistiqués et déclarer //TNotifyevents et de leur attribuer, mais permet de garder les choses simples :) . . .
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;
une liste D'objets peut contenir n'importe quel objet visuel ou non, mais cela vous donne un overhead ajouté de trier quels articles sont - mieux d'avoir des listes connexes si vous voulez des contrôles dynamiques multiples sur des panneaux similaires par exemple.
Note: Comme d'autres commentateurs, j'ai peut-être simplifié à l'excès par souci de brièveté, mais j'espère que vous saisirez l'idée. Vous avez besoin d'un mécanisme pour gérer les objets une fois qu'ils sont créés et les listes sont excellents pour ce genre de choses.
lors d'une recherche sur "la création d'un formulaire delphi en utilisant un modèle basé sur xml", je trouve quelque chose d'utile pointant RTTI et en utilisant l'api open tools (ToolsApi.pas je pense). Avoir un regard sur les interfaces de l'appareil.
Très à l'aise. Appel De Créer. Exemple:
procedure test
var
b : TButton;
begin
b:=TButton.Create(nil);
b.visible:=false;
end;
cela crée un component (TButton est un component) à l'exécution et définit la propriété visible.
pour le constructeur: passer zéro si vous voulez gérer la mémoire vous-même. Passer un pointeur à un autre composant, si vous voulez l'avoir détruit lorsque l'autre composant est détruit.
certains composants outrepassent la méthode' Loaded'. Cette méthode ne sera pas appelée automatiquement si vous créez une instance à l'exécution. Il sera appelé par Delphi lorsque le chargement à partir du fichier de formulaire (DFM) sera terminé.
si la méthode contient du code d'initialisation, votre application pourrait afficher un comportement inattendu lors de sa création à l'exécution. Dans ce cas, vérifiez si le composant écrivain a utilisé cette méthode.
si vous nichez, gagnez les contrôles dans les boîtes de groupe/les contrôles de Page / etc... Je pense que c'est bénéfique d'avoir la zone groupe parent également être le propriétaire. J'ai remarqué une nette diminution des périodes de fermeture des fenêtres en faisant cela, au lieu d'avoir le propriétaire toujours être la forme principale.
ceci est un exemple de la façon d'émuler l'étiquette de bouton sur 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.