2009-06-17 12 views

Odpowiedz

58

Zależy, czy jest to komponent wizualny, czy niewizualny. Zasada jest taka sama, ale istnieją pewne dodatkowe kwestie dotyczące każdego rodzaju komponentu.

Dla części niewizualnych

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

Dla wizualnych komponentów:

w istocie elementy wizualne są tworzone w taki sam sposób jak składniki non-wizualnych. Ale musisz ustawić dodatkowe właściwości, aby były widoczne.

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; 

Kilka objaśnienia do powyższego kodu:

  • przez ustawienie właściciela komponentu (parametr konstruktora) składnik ulega zniszczeniu, gdy formularz będącym właścicielem zostanie zniszczony.
  • Ustawienie właściwości Parent powoduje, że składnik jest widoczny. Jeśli go zapomnisz, twój komponent nie zostanie wyświetlony. (Łatwo przeoczyć, że jeden :))

Jeśli chcesz wiele składników można zrobić to samo co powyżej, ale w pętli:

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; 

Spowoduje to dodanie 10 przycisków po lewej stronie obramowanie formularza. Jeśli chcesz zmodyfikować przyciski później, możesz zapisać je na liście. (TComponentList ist najlepsza, ale także przyjrzeć się propozycji od komentarzach do tej odpowiedzi)

Jak przypisać obsługi zdarzeń:

Musisz utworzyć metodę obsługi zdarzenia i przypisać go do właściwość zdarzenia.

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

B := TButton.Create; 
//... 
B.OnClick := MyButtonClick; 
+1

Ale jeśli nie wiem na pewno, ile składników chcę utworzyć, np. jeśli zależy to od decyzji użytkownika. Jak mogę dynamicznie deklarować komponenty? –

+0

Rozróżnienie, czy przekazać zero, czy inny składnik, jako właściciel, nie ma nic wspólnego z widocznym komponentem, a jedynie z czasem życia obiektu. Niewidoczny komponent, który nie został uwolniony w tej samej metodzie, może zostać utworzony, podobnie jak w Twoim drugim fragmencie, i automatycznie zwolniony przez właściciela. – mghie

+0

s/visible/visual/g – mghie

0

Bardzo łatwa. Zadzwoń Utwórz. Przykład:

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

Spowoduje to utworzenie komponentu (TButton jest komponentem) w środowisku wykonawczym i ustawienie właściwości widocznej.


Dla konstruktora: przekazuj zero, jeśli chcesz samodzielnie zarządzać pamięcią. Przekaż wskaźnik innym komponentem, jeśli chcesz go zniszczyć, gdy inny komponent zostanie zniszczony.

+1

Istnieje potrzeba przekazania wskaźnika do właściciela elementu. TButton.Create (owner); –

+3

Ten kod nie wymaga kompilacji –

+0

> potrzeba właściciela Niekoniecznie. TButton.Create (zero); jest prawidłowy kod. ale musisz go teraz jawnie zniszczyć. Tworzenie elementów wizualnych z nikim właścicielem jest czasami przydatne. – Despatcher

23

Aby uprościć proces tworzenia komponentu środowiska wykonawczego, można użyć GExperts.

  1. Utwórz komponent (lub więcej komponentów) wizualnie i ustaw jego właściwości.
  2. Wybierz jeden lub więcej komponentów i uruchom komponenty GEX, składniki do kodu.
  3. Wklej wygenerowany kod do swojej aplikacji.
  4. Usuń komponenty z projektanta formularzy wizualnych.
(kod TButton-tworzenie generowane w ten sposób)

Przykład:

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

Świetna rada! Dokładnie to zasugerowałem. GExperts to doskonałe narzędzie do używania z Delphi. –

+0

... lub możesz zaprojektować go w edytorze wizualnym, a następnie zrobić pik w pliku .dfm. Zasadniczo dokładnie to samo jest w tekście – Earlz

+0

Gracias. Wolę pisać wszystko sam (wiem, że to może na nowo wymodelować koło, ale czuję na nim większą kontrolę) i wydaje się, że narzędzie GExpert nie zmienia się w czystym kodzie i że dźwięki są dobre. Jeszcze raz dziękuję za radę. – QMaster

1

Ale jeśli nie będę na pewno wiedzieć, ile składniki Chcę utworzyć, na przykład jeśli zależy to od decyzji użytkownika. Jak mogę dynamicznie deklarować komponenty?

Odpowiedź została zasugerowana - najprostszym sposobem jest lista obiektów (komponenty). TObjectList jest najprostszym w użyciu (w jednostkach contnrs). Listy są świetne!

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

// Można uzyskać bardziej wyrafinowane i deklarują // TNotifyevents i przypisać je, ale pozwala zachować to proste :) . . .

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; 

lista Obiekt może zawierać dowolny obiekt wizualny lub nie, ale to daje dodatkowy narzut sortowaniu, które elementy są które - lepiej mieć list związane, jeśli chcesz wiele formantów dynamicznych na podobnych paneli na przykład.

Uwaga: podobnie jak inni komentatorzy, mogłem zbytnio uprościć zwięzłość, ale mam nadzieję, że wpadliście na pomysł. Potrzebujesz mechanizmu do zarządzania obiektami po ich utworzeniu, a listy są doskonałe dla tego typu rzeczy.

0

Niektóre składniki zastępują metodę "Załadowany". Ta metoda nie zostanie wywołana automatycznie, jeśli utworzysz instancję w środowisku wykonawczym. Zostanie wywołany przez Delphi po zakończeniu ładowania z pliku formularza (DFM).

Jeśli metoda zawiera kod inicjowania, aplikacja może wyświetlać nieoczekiwane zachowanie po utworzeniu w środowisku wykonawczym. W takim przypadku sprawdź, czy komponent zapisujący użył tej metody.

0

Jeśli zagnieździsz kontrolki wygranych w polach grup/kontrolkach stron/itd ..., myślę, że korzystne jest, aby pole grupy nadrzędnej było również właścicielem. Zauważyłem gwałtowny spadek czasu zamknięcia okna podczas wykonywania tej czynności, w przeciwieństwie do tego, że właściciel zawsze był główną postacią.

1

Podczas badań nad "tworzeniem formularza delphi za pomocą szablonu opartego na XML", stwierdzam, że coś pożytecznego wskazuje na RTTI i korzystanie z otwartych narzędzi api (ToolsApi.pas, jak sądzę). Spójrz na interfejsy w urządzeniu.

4

Chciałbym dodać, że przy dynamicznym dodawaniu kontrolek ... dobrym pomysłem jest dodanie ich do listy obiektów (TObjectList) zgodnie z sugestią podaną w < 1> przez @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; 

Trzeba dodać moduł „Contnrs” do swojej listy zastosowań. I.e System.Contnrs.pas Podstawowa jednostka kontenerów Możesz mieć wiele list obiektów. Proponuję użyć obiektu TObjectList dla każdego rodzaju formantu, którego używasz, np. , np.

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 

pozwala to na łatwą manipulację/zarządzanie każdym kontrolerem, ponieważ wiesz jaki to rodzaj kontroli, np.

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; 

Pozwala to następnie użyć metod i właściwości tej kontroli Nie zapomnij stworzyć TObjectLists, być może w postaci stworzyć imprezę ...

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

To jest przykład jak emulować znacznik przycisku w 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.