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.)?

19
demandé sur Lukáš Neoproud 2009-06-17 10:12:06

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;
60
répondu Daniel Rikowski 2010-08-05 09:09:51

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

  1. Créer un composant (ou plus) visuellement et définir ses propriétés.
  2. sélectionnez un ou plusieurs composants et exécutez GExperts, Components to Code.
  3. collez le code généré dans votre application.
  4. 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;
23
répondu gabr 2009-06-17 07:22:42

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;
4
répondu Darren 2012-10-14 06:56:42

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.

1
répondu Despatcher 2009-06-17 11:20:45

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.

1
répondu user114285 2009-06-19 13:32:18

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.

0
répondu Tobias Langner 2009-06-17 11:53:31

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.

0
répondu mjn 2009-06-17 14:07:42

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.

0
répondu Peter Turner 2009-06-17 15:32:11

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.
-1
répondu Mohammad Yusuf 2013-04-03 07:19:36