Как я могу создать компонент во время выполнения, а затем работать с ним (изменение свойств и т.д.)?
Создание компонентов во время выполнения - Delphi
Ответ 1
Это зависит от того, является ли это визуальным или невизуальным компонентом. Принцип тот же, но есть некоторые дополнительные соображения для каждого типа компонента.
Для не визуальных компонентов
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;
Ответ 2
Чтобы упростить процесс создания компонента времени выполнения, вы можете использовать GExperts.
- Визуально создайте компонент (или несколько компонентов) и задайте его свойства.
- Выберите один или несколько компонентов и выполните команды GExperts, Components to Code.
- Вставьте сгенерированный код в ваше приложение.
- Удалить компонент из конструктора визуальной формы.
Пример (код создания 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;
Ответ 3
Я просто хотел бы добавить, что при динамическом добавлении элементов управления... это хорошая идея добавить их в список объектов (TObjectList), как предложено в < 1 > byDespatcher.
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" в список "Uses". 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 event...
checkBoxCntrlsList := TObjectList.Create;
comboboxCntrlsList := TObjectList.Create;
Ответ 4
Но если я не знаю, сколько компонентов я хочу создать, например. если это зависит от решения пользователя. Итак, как я могу объявить компоненты динамически?
Был предложен ответ - самым простым способом является список объектов (компонентов). 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;
Список объектов может содержать любой объект визуальный или нет, но это дает дополнительные накладные расходы на сортировку, какие элементы - что лучше иметь связанные списки, если вы хотите, например, несколько динамических элементов управления на подобных панелях.
Примечание. Как и другие комментаторы, я, возможно, слишком упрощен для краткости, но надеюсь, что вы идете. Вам нужен механизм для управления объектами после их создания, и списки отлично подходят для этого материала.
Ответ 5
Во время исследования "создания формы delphi с использованием шаблона на основе xml" я нахожу что-то полезное, указывающее RTTI и использующее открытые инструменты api (ToolsApi.pas, я думаю). Посмотрите интерфейсы в устройстве.
Ответ 6
Очень легко. Вызовите Создать. Пример:
procedure test
var
b : TButton;
begin
b:=TButton.Create(nil);
b.visible:=false;
end;
Это создает компонент (TButton является компонентом) во время выполнения и устанавливает видимость свойства.
Для конструктора: передайте nil, если вы хотите самостоятельно управлять памятью. Передайте указатель другому компоненту, если вы хотите, чтобы он был уничтожен при уничтожении другого компонента.
Ответ 7
Некоторые компоненты переопределяют метод Loaded. Этот метод не будет вызываться автоматически, если вы создадите экземпляр во время выполнения. Он будет вызываться Delphi при загрузке из файла формы (DFM).
Если этот метод содержит код инициализации, ваше приложение может проявлять неожиданное поведение при создании во время выполнения. В этом случае проверьте, использовал ли этот компонент этот метод.
Ответ 8
Если вы устанавливаете элементы управления победой в Group Boxes/Page Controls/Etc..., я думаю, что полезно, чтобы поле родительской группы также было владельцем. Я заметил резкое уменьшение времени закрытия окна при выполнении этого, в отличие от того, что владелец всегда был основной формой.
Ответ 9
Это пример того, как эмулировать тег кнопки на 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.