delphi runtime components

Creando componentes en tiempo de ejecución-Delphi



runtime components (9)

Pero si no sé cuántos componentes quiero crear, por ejemplo, si depende de la decisión del usuario. Entonces, ¿cómo puedo declarar componentes dinámicamente?

Se ha sugerido la respuesta: la forma más sencilla es una Lista de objetos (componentes). TObjectList es el más simple de usar (en contadores de unidad). ¡Las listas son geniales!

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

// Puede ser más sofisticado y declarar // TNotifyevents y asignarlos, pero sea sencillo :). . .

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;

Una lista de objetos puede contener cualquier objeto visual o no, pero eso le brinda una sobrecarga adicional de ordenar qué elementos son cuáles: mejor tener listas relacionadas si desea múltiples controles dinámicos en paneles similares, por ejemplo.

Nota: al igual que otros comentaristas, es posible que haya sido simplificado en exceso por brevedad, pero espero que sea una idea más acertada. Necesita un mecanismo para administrar los objetos una vez que se crean y las listas son excelentes para esto.

¿Cómo puedo crear un componente en tiempo de ejecución y luego trabajar con él (cambiar propiedades, etc.)?


Algunos componentes anulan el método ''Cargado''. Este método no se llamará automáticamente si crea una instancia en tiempo de ejecución. Delphi lo llamará cuando se complete la carga desde el archivo de formulario (DFM).

Si el método contiene código de inicialización, su aplicación puede mostrar un comportamiento inesperado cuando se crea en tiempo de ejecución. En este caso, compruebe si el escritor de componentes ha utilizado este método.


Depende si es un componente visual o no visual. El principio es el mismo, pero hay algunas consideraciones adicionales para cada tipo de componente.

Para componentes no visuales.

var C: TMyComponent; begin C := TMyComponent.Create(nil); try C.MyProperty := MyValue; //... finally C.Free; end; end;

Para componentes visuales:

En esencia, los componentes visuales se crean de la misma manera que los componentes no visuales. Pero tienes que establecer algunas propiedades adicionales para hacerlas 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;

Algunas explicaciones al código anterior:

  • Al establecer el propietario del componente (el parámetro del constructor), el componente se destruye cuando se destruye la forma propietaria.
  • Establecer la propiedad Parent hace que el componente sea visible. Si lo olvidas tu componente no se mostrará. (Es fácil perdérsela)

Si desea muchos componentes , puede hacer lo mismo que arriba pero en un bucle:

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;

Esto agregará 10 botones en el borde izquierdo del formulario. Si desea modificar los botones más tarde, puede almacenarlos en una lista. ( TComponentList es el más adecuado, pero también echa un vistazo a las propuestas de los comentarios a esta respuesta)

Cómo asignar controladores de eventos:

Debe crear un método de controlador de eventos y asignarlo a la propiedad del evento.

procedure TForm1.MyButtonClick(Sender: TObject); var Button: TButton; begin Button := Sender as TButton; ShowMessage(Button.Caption + '' clicked''); end; B := TButton.Create; //... B.OnClick := MyButtonClick;


Durante una investigación sobre "crear un formulario Delphi usando una plantilla basada en xml", encuentro algo útil al señalar RTTI y usar una api de herramientas abiertas (creo que ToolsApi.pas). Echa un vistazo a las interfaces en la unidad.


Muy fácil. Llamar a crear. Ejemplo:

procedure test var b : TButton; begin b:=TButton.Create(nil); b.visible:=false; end;

Esto crea un componente (TButton es un componente) en tiempo de ejecución y establece la propiedad visible.

Para el constructor: pase nil si quiere administrar la memoria usted mismo. Pase un puntero a otro componente si desea destruirlo cuando se destruya el otro componente.


Para simplificar el proceso de creación del componente de tiempo de ejecución, puede utilizar GExperts .

  1. Cree un componente (o más componentes) visualmente y establezca sus propiedades.
  2. Seleccione uno o más componentes y ejecute GExperts, Componentes a Código.
  3. Pegue el código generado en su aplicación.
  4. Elimine los componentes del diseñador visual de formas.

Ejemplo (código de creación de TButton generado de esta manera):

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;


Si anida los controles de ganancia en Cuadros de grupo / Controles de página / Etc ..., creo que es beneficioso que el cuadro de grupo principal también sea el propietario. He notado una gran disminución en los tiempos de cierre de la ventana al hacer esto, en lugar de tener al propietario siempre como el formulario principal.


Solo me gustaría agregar que al agregar controles dinámicamente ... es una buena idea agregarlos a una lista de objetos (TObjectList) como se sugiere en <1> por @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;

Debe agregar la Unidad ''Contnrs'' a su lista de Usos. Es decir, System.Contnrs.pas la unidad de contenedores base Y puede tener muchas listas de objetos. Sugiero usar un TObjectList para cada tipo de control que use, por ejemplo,

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

esto le permite manipular / administrar fácilmente cada control, ya que sabrá qué tipo de control es, por ejemplo,

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;

Esto le permite usar los métodos y las propiedades de ese control. No se olvide de crear las listas de objetos, tal vez en el formulario crear evento ...

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


Este es un ejemplo de cómo emular una etiqueta de botón en 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.