2009-06-17 111 views

回答

58

它取決於它是否是視覺或非視覺組件。原理是一樣的,但是對於每種組件都有一些額外的考慮。

對於非可視化組件

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; 
0

非常容易。致電創建。示例:

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

這會在運行時創建一個組件(TButton是一個組件)並將該屬性設置爲可見。


對於構造函數:如果您想自己管理內存,則傳遞nil。如果您希望在另一個組件被銷燬時銷燬它,則傳遞另一個組件的指針。

+1

需要將指針傳遞給元素的所有者。 TButton.Create(所有者); – 2009-06-17 06:17:13

+3

此代碼不會編譯 – 2009-06-17 06:24:11

+0

>需要所有者 不一定。 TButton.Create(無);是有效的代碼。但是你現在需要明確地銷燬它。用零業主創建可視化組件有時候很有用。 – Despatcher 2009-06-17 13:30:02

23

爲了簡化運行時組件的創建過程,您可以使用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; 
1

但是,如果我不肯定知道我要多少組件來創建,例如如果這取決於用戶的決定。那麼我怎樣才能動態地聲明組件?

答案已經被提出 - 最簡單的方法是對象列表(組件)。 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

某些組件重寫'Loaded'方法。如果您在運行時創建實例,則不會自動調用此方法。當從表單文件(DFM)加載完成時,它將由Delphi調用。

如果該方法包含初始化代碼,則在運行時創建應用程序時可能會顯示意外的行爲。在這種情況下,檢查組件編寫器是否使用了此方法。

0

如果你在組合框/頁面控件/其他中嵌套win控件,我認爲讓父組框也是所有者是有益的。我注意到這樣做時窗戶關閉時間急劇減少,而不是讓所有者始終成爲主要窗體。

1

在「使用基於xml的模板創建delphi表單」的研究中,我發現了一些有用的指出RTTI並使用開放工具api(ToolsApi.pas我認爲)的方法。查看設備中的接口。

4

我只想補充一點,當動態添加控件時... 按照@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; 

您需要將Unit'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,也許在表單中創建活動...

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

這是例子如何在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.