Question

Comment puis-je créer un composant au moment de l'exécution et ensuite l'utiliser (modification des propriétés, etc.)?

Était-ce utile?

La solution

Cela dépend s'il s'agit d'un composant visuel ou non visuel. Le principe est le même, mais il existe des 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 (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 rater celui-là :))

Si vous souhaitez plusieurs composants , vous pouvez procéder comme 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;

Ceci ajoutera 10 boutons au bord 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 coup d'oeil à la propositions des commentaires à cette réponse)

Comment attribuer 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;

Autres conseils

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

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

Exemple (code de création de boutons créé 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 que 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 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 / gérer facilement chaque contrôle car vous saurez 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;

Ceci 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 créer un événement ...

checkBoxCntrlsList := TObjectList.Create;
comboboxCntrlsList := TObjectList.Create;
  

Mais si je ne sais pas trop 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 manière dynamique?

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). Les listes sont géniales!

  In Form1 Public
  MyList: TObjectList;
  procedure AnyButtonClick(Sender: TObject); 

// Vous pouvez devenir plus sophistiqué et déclarer // TNotifyevents et les assigner, mais restons 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 charge supplémentaire de trier quels sont les éléments. Il vaut mieux avoir des listes associées si vous souhaitez plusieurs contrôles dynamiques sur des panneaux similaires, par exemple.

Remarque: comme d’autres commentateurs, j’ai peut-être simplifié à outrance pour simplifier les choses, mais j’espère que vous comprendrez. 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.

Au cours d'une recherche sur & "Créer un formulaire Delphi à l'aide d'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 coup d’œ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;

Ceci crée un composant (TButton est un composant) au moment de l'exécution et rend la propriété visible.

Pour le constructeur: passez nil si vous souhaitez gérer vous-même la mémoire. Passez un pointeur sur un autre composant si vous souhaitez le faire détruire lorsque ce dernier 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 présenter un comportement inattendu lors de sa création au moment de l'exécution. Dans ce cas, vérifiez si le créateur du composant a utilisé cette méthode.

Si vous imbriquez des contrôles gagnants dans des 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 constaté une nette diminution du nombre de fois que la fenêtre est fermée, alors que le propriétaire est toujours le formulaire principal.

Voici un exemple d'émulation de balise 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.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top