Создание компонентов во время выполнения - Delphi - PullRequest
20 голосов
/ 17 июня 2009

Как я могу создать компонент во время выполнения и затем работать с ним (изменение свойств и т. Д.)?

Ответы [ 9 ]

64 голосов
/ 17 июня 2009

Зависит от того, является ли это визуальным или невизуальным компонентом. Принцип тот же, но есть некоторые дополнительные соображения для каждого вида компонентов.

Для невизуальных компонентов

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

Для визуальных компонентов:

По сути, визуальные компоненты создаются так же, как невизуальные компоненты. Но вы должны установить некоторые дополнительные свойства, чтобы сделать их видимыми.

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;

Несколько пояснений к коду выше:

  • При установке владельца компонента (параметра конструктора) компонент уничтожается при уничтожении формы-владельца.
  • Установка свойства Parent делает компонент видимым. Если вы забудете об этом, ваш компонент не будет отображаться. (Это легко пропустить :))

Если вы хотите много компонентов , вы можете сделать то же, что и выше, но в цикле:

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;

Это добавит 10 кнопок на левой границе формы. Если вы хотите изменить кнопки позже, вы можете сохранить их в списке. ( TComponentList лучше всего подходит, но также посмотрите на предложения из комментариев к этому ответу)

Как назначить обработчики событий:

Вы должны создать метод обработчика события и назначить его свойству события.

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

B := TButton.Create;
//...
B.OnClick := MyButtonClick;
24 голосов
/ 17 июня 2009

Чтобы упростить процесс создания компонента среды выполнения, вы можете использовать GExperts .

  1. Создайте компонент (или несколько компонентов) визуально и установите его свойства.
  2. Выберите один или несколько компонентов и выполните GExperts, Компоненты для кода.
  3. Вставьте сгенерированный код в ваше приложение.
  4. Удалить компонент (ы) из визуального конструктора форм.

Пример (код создания TButton, сгенерированный таким образом):

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;
4 голосов
/ 14 октября 2012

Я просто хотел бы добавить это при динамическом добавлении элементов управления ... было бы неплохо добавить их в список объектов (TObjectList), как предложено в <1> @ 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;

Вам необходимо добавить юнит 'Contnrs' в ваш список использования. I.e System.Contnrs.pas базовый блок контейнеров И вы можете иметь много списков объектов. Я предлагаю использовать TObjectList для каждого типа элемента управления, который вы используете например,

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

это позволяет вам легко манипулировать / управлять каждым элементом управления, поскольку вы будете знать, к какому типу управления это относится, например,

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;

Это позволяет вам затем использовать методы и свойства этого элемента управления. Не забудьте создать списки TObjectLists, возможно, в форме события create ...

checkBoxCntrlsList := TObjectList.Create;
comboboxCntrlsList := TObjectList.Create;
1 голос
/ 19 июня 2009

Во время исследования «создания формы delphi с использованием шаблона на основе xml» я нашел кое-что полезное, указывая RTTI и используя открытые инструменты api (ToolsApi.pas, я думаю). Посмотрите на интерфейсы в устройстве.

1 голос
/ 17 июня 2009

Но если я точно не знаю, сколько компонентов я хочу создать, например, если это зависит от решения пользователя. Итак, как я могу объявить компоненты динамически?

Был предложен ответ - самый простой способ - это список объектов (компонентов). TObjectList является самым простым в использовании (в единицах подключения). Списки отличные!

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

// Вы можете получить более сложные и объявить // TNotifyevents и назначить их, но давайте сделаем это просто :) , , .

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;

Список объектов может содержать любой визуальный объект или нет, но это дает вам дополнительные накладные расходы при сортировке того, какие элементы какие - лучше иметь связанные списки, если вы хотите, например, несколько динамических элементов управления на похожих панелях.

Примечание: как и другие комментаторы, я, возможно, слишком упрощен для краткости, но я надеюсь, что вы поняли идею. Вам нужен механизм для управления объектами после их создания, и списки отлично подходят для этого.

0 голосов
/ 03 апреля 2013

Это пример того, как эмулировать тег кнопки на 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.
0 голосов
/ 17 июня 2009

Если вы вкладываете элементы управления выигрышем в групповые блоки / элементы управления страницами / и т. Д., Я думаю, что полезно, чтобы родительская групповая ячейка также была владельцем. При этом я заметил резкое уменьшение времени закрытия окна, в отличие от того, чтобы владелец всегда был главной формой.

0 голосов
/ 17 июня 2009

Некоторые компоненты переопределяют метод Loaded. Этот метод не будет вызываться автоматически, если вы создаете экземпляр во время выполнения. Он будет вызываться Delphi при завершении загрузки из файла формы (DFM).

Если метод содержит код инициализации, ваше приложение может показать непредвиденное поведение при создании во время выполнения. В этом случае проверьте, использовал ли средство записи компонента этот метод.

0 голосов
/ 17 июня 2009

Очень легко. Звоните Создать. Пример:

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

Это создает компонент (TButton - это компонент) во время выполнения и устанавливает свойство видимым.


Для конструктора: передайте nil, если вы хотите управлять памятью самостоятельно. Передайте указатель другому компоненту, если вы хотите уничтожить его при уничтожении другого компонента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...