Tento trik určitě většina programátorů zná, ale třeba to někomu pomůže a mimochodem to ukazuje genialitu návrhu Delphi.
Jistě je Vám známo co jsou to frames - jedná se o pseudo okna, která můžete v IDE designovat a pak je používat v jiných formulářích. Je to celkem slušné řešení,
ale není to úplně ono. Má to jisté omezení, sem tam IDE nefunguje 100% podle toho co si představuji atd. Postupně jsem přešel na méně RAD přístup, a to "injektování" formuláře do jiného controlu na jiném formuláři (já tomu říkám osobně dokování, ale dokování je v Delphi něco jiného).
Pro mne je to velmi flexibilní věc: např. můžete jiné formuláře injektovat do dynamicky vytvářených záložek PageControlu, nebo stejný formulář můžete přímo zobrazit atd. Za mne je hlavním důvodem modularita, případně OnCreate atd.
Mějme dva formuláře: na jednom bude panel, do kterého budeme injektovat za běhu jiný formulář (tj. formulář 2) , např. s TMemo (nebo samozřejmě s čímkoliv jiným).
Navíc si k panelu přidáme dvě tlačítka, ať se nám to pro začátek lépe ladí. Jedno tlačítko formulář injektuje, druhého uvolní.
type
TForm21 = class(TForm)
Panel1: TPanel;
btnDock: TButton;
btnFree: TButton;
procedure btnDockClick(Sender: TObject);
procedure btnFreeClick(Sender: TObject);
private
{ Private declarations }
FAnotherForm: TForm22;
public
{ Public declarations }
end;
var
Form21: TForm21;
implementation
{$R *.dfm}
Abych parafrázoval klasika: pokud se v prvním jednání objeví na stěně puška, musí ve třetím jednání vystřelit. Takže pokud máme v deklaraci metody, musíme je implementovat:
procedure TForm21.btnDockClick(Sender: TObject);
begin
// dock
FAnotherForm := TForm22.Create(Self);
FAnotherForm.Parent := Panel1;
FAnotherForm.Align := alClient;
FAnotherForm.BorderIcons := [];
FAnotherForm.BorderStyle := bsNone;
FAnotherForm.Show;
FAnotherForm.Memo1.Text :='delphi.cz';
end;
procedure TForm21.btnFreeClick(Sender: TObject);
begin
FAnotherForm.Parent := nil;
// Self.RemoveComponent(FAnotherForm);
FreeAndNil(FAnotherForm);
end;
První obsluha je celkem jasná, vytvoříme instanci formuláře (vlastníkem, a tedy ten kdo ho uvolní je formulář via Self), přes Parent ho přiřadíme do panelu.
Tohle je častý omyl u začátečníků - nepleťte si vlastníka (toho kdo bude objekt uvolňovat v okamžiku kdy vlastník zanikne) a ten prvek, který bude vizuálním otcem. Mohl bych napsat jako vlastníka Panel1, a bylo by to korektní - ale takto se můj formulář zruší, až se zruší ten druhý formulář. Mezitím mohu cvičit s Panel1 a nebude to mít vliv na život injektovaného formuláře. Možná to trošku komplikuji, ale chtěl jsem ukázat, že vlastník a parent nemusí být ten sám.
Pokud neprovedete přiřazení Parent tak neuvidíte nic, ale objekt bude existovat.
Několik málo komponent nemá dostupný Parent (myslím, že např. TWebBrowser), pokud mermomocí potřebujete Parent i v těchto případech, můžete použít háček s přetypováním na předchůdce.
Další řádky v uvedené metodě jen schovávají některé prvky formuláře a formulář zobrazí.
Druhá metoda je odstranění dynamicky injektovaného prvku. Pro jistotu - Delphi automaticky při uvolnění vlastníka uvolní i injektovaný formulář, ale někdy to chcete udělat sami - třeba protože tam chcete injektovat něco jiného. Mimochodem v těchto případech není třeba vždy uvolňovat, stačí jen pracovat s Parent (vhodně nastavit na nil atd., a zase zpět). Prakticky stačí jen to volání Free, to provede ty ostatní věci uvedené před ním.
Tento princip Vám např. umožní dynamicky dokovat Váš toolbar z okna někam jinam, třeba do Ribbonu.