web-dev-qa-db-fra.com

Création de composants à l'exécution - Delphi

Comment puis-je créer un composant lors de l'exécution et ensuite travailler avec lui (modification des propriétés, etc.)?

21
Lukáš Neoproud

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:

  • En définissant le propriétaire du composant (le paramètre du constructeur), le composant est détruit lorsque le formulaire propriétaire est détruit.
  • La définition de la propriété 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;
68
Daniel Rikowski

Pour simplifier le processus de création de composants d'exécution, vous pouvez utiliser GExperts .

  1. Créez visuellement un composant (ou plusieurs composants) et définissez ses propriétés.
  2. Sélectionnez un ou plusieurs composants et exécutez GExperts, Composants à coder.
  3. Collez le code généré dans votre application.
  4. Supprimez les composants du concepteur de formulaire visuel.

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;
24
gabr

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;
4
Darren

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.

1
Despatcher

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é.

1
user114285

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.

0
Tobias Langner

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.

0
mjn

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.

0
Peter Turner