Jak utworzyć komponent w środowisku wykonawczym, a następnie pracować z nim (zmiana właściwości itp.)?Tworzenie komponentów w czasie wykonywania - Delphi
Odpowiedz
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;
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.
Istnieje potrzeba przekazania wskaźnika do właściciela elementu. TButton.Create (owner); –
Ten kod nie wymaga kompilacji –
> 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
Aby uprościć proces tworzenia komponentu środowiska wykonawczego, można użyć GExperts.
- Utwórz komponent (lub więcej komponentów) wizualnie i ustaw jego właściwości.
- Wybierz jeden lub więcej komponentów i uruchom komponenty GEX, składniki do kodu.
- Wklej wygenerowany kod do swojej aplikacji.
- Usuń komponenty z projektanta formularzy wizualnych.
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;
Świetna rada! Dokładnie to zasugerowałem. GExperts to doskonałe narzędzie do używania z Delphi. –
... 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
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
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.
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.
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ą.
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.
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;
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.
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? –
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
s/visible/visual/g – mghie