런타임에 컴포넌트 생성 - Delphi
-
05-07-2019 - |
문제
런타임에 구성 요소를 생성한 다음 작업(속성 변경 등)하려면 어떻게 해야 합니까?
해결책
시각적이거나 시각적이지 않은 구성 요소인지 여부에 따라 다릅니다. 원리는 동일하지만 각 종류의 구성 요소에 대해 몇 가지 추가 고려 사항이 있습니다.
비 시각 구성 요소의 경우
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 IST는 가장 적합하지만 의견 에서이 답변에 대한 제안을 살펴보십시오)
이벤트 처리기를 지정하는 방법 :
이벤트 핸들러 메소드를 작성하고 이벤트 속성에 할당해야합니다.
procedure TForm1.MyButtonClick(Sender: TObject);
var
Button: TButton;
begin
Button := Sender as TButton;
ShowMessage(Button.Caption + ' clicked');
end;
B := TButton.Create;
//...
B.OnClick := MyButtonClick;
다른 팁
런타임 구성 요소 생성 프로세스를 단순화하려면 사용할 수 있습니다. gexperts.
- 구성 요소 (또는 더 많은 구성 요소)를 시각적으로 생성하고 속성을 설정하십시오.
- 하나 이상의 구성 요소를 선택하고 코드에 대한 구성 요소, 구성 요소를 실행하십시오.
- 생성 된 코드를 응용 프로그램에 붙여 넣습니다.
- 시각적 형태 디자이너에서 구성 요소를 제거하십시오.
예제 (이러한 방식으로 생성 된 Tbutton-kreation 코드) :
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;
동적으로 컨트롤을 추가할 때 추가하고 싶습니다.@Despatcher가 <1>에서 제안한 대로 개체 목록(TObjectList)에 추가하는 것이 좋습니다.
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' 유닛을 추가해야 합니다.IE 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;
이렇게하면 해당 제어의 메소드와 속성을 사용할 수 있습니다. 아마도 양식 작성 이벤트에서 TobjectList를 만드는 것을 잊지 마십시오 ...
checkBoxCntrlsList := TObjectList.Create;
comboboxCntrlsList := TObjectList.Create;
그러나 내가 얼마나 많은 구성 요소를 만들고 싶은지 모르면 사용자의 결정에 따라 다르면. 그렇다면 구성 요소를 어떻게 동적으로 선언 할 수 있습니까?
대답은 제안되었습니다 - 가장 쉬운 방법은 객체 (구성 요소)의 목록입니다. TobjectList는 사용하기가 가장 간단합니다 (단위 Contnrs). 목록은 훌륭합니다!
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;
객체 목록에는 객체 비주얼이 포함될 수 있지만 예를 들어 유사한 패널에서 여러 동적 컨트롤을 원하는 경우 관련 목록을 갖는 것이 어떤 항목을 분류 할 수있는 추가 오버 헤드가 제공됩니다.
참고 : 다른 의견 제시 자들과 마찬가지로 간결성에 대해 과도하게 단순화했을 수도 있지만 아이디어를 기르기를 바랍니다. 객체가 생성되면 객체를 관리하는 메커니즘이 필요 하며이 내용에 적합합니다.
"XML 기반 템플릿을 사용하여 델파이 양식 만들기"에 대한 연구에서 RTTI를 가리키고 Open Tools API (ToolSapi.Pas)를 사용하는 유용한 것이 있습니다. 장치의 인터페이스를 살펴보십시오.
매우 쉽습니다. Cale Create를 호출하십시오. 예시:
procedure test
var
b : TButton;
begin
b:=TButton.Create(nil);
b.visible:=false;
end;
이것은 런타임에 구성 요소 (tbutton은 구성 요소)를 생성하고 속성을 볼 수 있습니다.
생성자의 경우 : 메모리를 직접 관리하려면 NIL을 통과하십시오. 다른 구성 요소가 파괴 될 때 파괴하려면 다른 구성 요소를 전달하십시오.
일부 구성 요소는 '로드 된'방법을 무시합니다. 런타임에 인스턴스를 만드는 경우이 메소드는 자동으로 호출되지 않습니다. 양식 파일 (DFM)에서로드 할 때 Delphi가 호출합니다.
메소드에 초기화 코드가 포함 된 경우 런타임에 생성 될 때 응용 프로그램에 예기치 않은 동작이 표시 될 수 있습니다. 이 경우 구성 요소 작성자 가이 방법을 사용했는지 확인하십시오.
그룹 상자/페이지 컨트롤/etc에서 컨트롤을 둥지하면 부모 그룹 상자도 소유자가되는 것이 유리하다고 생각합니다. 소유자가 항상 주요 형태가되는 것과는 달리이 작업을 수행 할 때 창 가까운 시간이 급격히 감소하는 것을 보았습니다.
이것은 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.