Comment puis-je créer un composant lors de l'exécution et ensuite travailler avec lui (modification des propriétés, etc.)?
Cela dépend s'il s'agit d'un composant visuel ou non visuel. Le principe est le même, mais il existe quelques 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 composants visuels:
En substance, les composants visuels sont créés de la même manière que les composants non visuels. Mais vous devez définir des 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 sur le code ci-dessus:
Parent
rend le composant visible. Si vous l'oubliez, votre composant ne sera pas affiché. (Il est facile de manquer celui-là :))Si vous voulez de nombreux composants vous pouvez faire la même chose que ci-dessus mais en 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 ultérieurement, vous pouvez les stocker dans une liste. ( TComponentList est le mieux adapté, mais jetez également un œil aux propositions des commentaires de cette réponse)
Comment affecter des gestionnaires d'événements:
Vous devez créer une méthode de gestionnaire d'événements et l'affecter à 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 de composants d'exécution, vous pouvez utiliser GExperts .
Exemple (code de création TButton généré de cette manière):
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 cela lors de l'ajout dynamique de contrôles ... c'est 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 d'utilisations. I.e System.Contnrs.pas l'unité de base des conteneurs Et vous pouvez avoir de nombreuses listes d'objets. Je suggère d'utiliser une 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/gérer facilement chaque contrôle car vous saurez de quel type de contrôle il s'agit, 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 ensuite 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 événement create ...
checkBoxCntrlsList := TObjectList.Create;
comboboxCntrlsList := TObjectList.Create;
Mais si je ne sais pas exactement combien de composants je veux créer, par ex. si cela dépend de la décision de l'utilisateur. Alors, comment puis-je déclarer des composants dynamiquement?
La réponse a été suggérée - le moyen le plus simple est une liste d'objets (composants). TObjectList est le plus simple à utiliser (en unités de contenu). Les listes sont super!
In Form1 Public
MyList: TObjectList;
procedure AnyButtonClick(Sender: TObject);
// Vous pouvez devenir plus sophistiqué et déclarer // TNotifyevents et les assigner mais laisse 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 une surcharge supplémentaire pour trier les éléments qui sont - mieux d'avoir des listes associées si vous voulez plusieurs contrôles dynamiques sur des panneaux similaires par exemple.
Remarque: comme d'autres commentateurs, j'ai peut-être trop simplifié par souci de concision, mais j'espère que vous avez 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 excellentes 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 en soulignant RTTI et en utilisant des outils ouverts api (ToolsApi.pas je pense). Jetez un œil aux interfaces de l'unité.
Très facile. Appelez Créer. Exemple:
procedure test
var
b : TButton;
begin
b:=TButton.Create(nil);
b.visible:=false;
end;
Cela crée un composant (TButton est un composant) au moment de l'exécution et définit la propriété visible.
Pour le constructeur: passez nil si vous voulez gérer vous-même la mémoire. Passez un pointeur sur un autre composant si vous souhaitez le faire détruire lorsque l'autre composant est détruit.
Certains composants remplacent la méthode "Loaded". Cette méthode ne sera pas appelée automatiquement si vous créez une instance au moment de 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 peut afficher un comportement inattendu lors de sa création au moment de l'exécution. Dans ce cas, vérifiez si le rédacteur de composants a utilisé cette méthode.
Si vous imbriquez des contrôles de gain dans les zones de groupe/contrôles de page/etc., je pense qu'il est avantageux que la zone de groupe parent soit également le propriétaire. J'ai remarqué une nette diminution du temps de fermeture des fenêtres lors de cette opération, par opposition au fait que le propriétaire soit toujours le formulaire principal.