Pergunta

Como posso criar um componente em tempo de execução e, em seguida, trabalhar com ele (como alterar as propriedades, etc.)?

Foi útil?

Solução

Depende se é um componente visual ou não visual. O princípio é o mesmo, mas há algumas considerações adicionais para cada tipo de componente.

Para componentes não-visuais

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

Para componentes visuais:

componentes visuais, em essência, são criados no da mesma maneira que os componentes não-visuais. Mas você tem que definir algumas propriedades adicionais para torná-los visíveis.

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;

Algumas explicações para o código acima:

  • Ao definir o proprietário do componente (o parâmetro do construtor) o componente é destruída quando o formulário possuir é destruído.
  • Definir a propriedade Parent torna visível o componente. Se você esquecer seu componente não será exibido. (É fácil perder que um :))

Se você quiser muitos componentes você pode fazer o mesmo que acima, mas em um loop:

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;

Isto irá adicionar 10 botões na borda esquerda do formulário. Se você deseja modificar os botões mais tarde, você pode armazená-los em uma lista. ( TComponentList ist o mais adequado, mas também ter um olhar para o propostas dos comentários a esta resposta)

Como manipuladores de eventos atribuir:

Você tem que criar um método de manipulador de eventos e atribuí-lo à propriedade de 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;

Outras dicas

Para simplificar o processo de criação do componente de tempo de execução, você pode usar GExperts .

  1. Criar um componente (ou mais componentes) visualmente e definir as suas propriedades.
  2. Selecione um ou mais componentes e executar GExperts, Componentes para código.
  3. Cole o código gerado em sua aplicação.
  4. componente Remove (s) do designer de forma visual.

Exemplo (código TButton-criação gerado desta maneira):

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;

Eu gostaria apenas de acrescentar que ao adicionar dinamicamente controles ... -lo como uma boa idéia para adicioná-los a uma lista de objetos (TObjectList) como sugerido em <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;

Você precisa adicionar a Unidade 'Contnrs' à sua lista de usos. Ou seja System.Contnrs.pas a Unidade Contentores de base E você pode ter muitas listas de objetos. Eu sugiro usar um TObjectList para cada tipo de controle que você usa por exemplo.

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

isso permite que você manipule / gerenciar cada controle como você vai saber que tipo de controle é por exemplo facilmente.

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;

Isso permite que você use os métodos e propriedades do que o controle Não se esqueça de criar as TObjectLists, talvez sob a forma criar evento ...

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

Mas se eu não certamente sabe quantos componentes Quero criar, por exemplo, se depender da decisão do usuário. Então, como posso declarar componentes dinamicamente?

A resposta foi sugerida - a maneira mais fácil é uma lista de objetos (componentes). TObjectList é o mais simples de usar (em contnrs unidade). As listas são ótimo!

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

// Você pode obter mais sofisticados e declarar // TNotifyevents e atribuí-los, mas vamos mantê-lo 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;

Uma lista de objeto pode conter qualquer objeto visual ou não, mas que lhe dá um adicional sobrecarga de separar quais itens são que -. Melhor ter listas relacionadas Se quiser vários controles dinâmicos em painéis semelhantes para instância

Nota: como outros comentadores eu possa ter mais simplificada para a brevidade, mas eu espero que você ge a idéia. Você precisa de um mecanismo para gerenciar os objetos quando eles são criados e listas são excelentes para este material.

Durante uma pesquisa sobre "a criação de uma forma delphi usando o modelo baseado em XML", eu encontrar algo que aponta útil fora RTTI e usando aberto ferramentas de api (ToolsApi.pas eu acho). Ter um olhar para as interfaces na unidade.

Muito facilidade. Chamada Criar. Exemplo:

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

Isso cria um componente (TButton é um componente) em tempo de execução e define a propriedade visível.


Para o construtor: passar nil se pretende gerir a memória sozinho. Passar um ponteiro outro componente se você quiser tê-lo destruído quando o outro componente é destruído.

Alguns componentes substituir o método 'Loaded'. Este método não será chamado automaticamente se você criar uma instância em tempo de execução. Ele será chamado pelo Delphi quando o carregamento do arquivo de formulário (DFM) está completa.

Se o método contém código de inicialização, o aplicativo pode apresentar um comportamento inesperado quando criado em tempo de execução. Neste caso, verifique se o escritor componente tem utilizado este método.

Se você ninho ganhar controles no Grupo Boxes / Controles Página / etc ..., eu acho que é benéfico ter a caixa de grupo pai também ser o proprietário. Tenho notado uma diminuição acentuada nos tempos fechar janela ao fazer isso, em vez de ter o proprietário sempre ser a principal forma.

Esta é exemplo como emular tag botão no 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.
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top