![]() |
'TMyForm' nach TMyForm casten ? ("lebendig" werden
Hallo,
hier mal eine gaaanz verwegene Frage : (ist vermutlich Unsinn, aber wer weiss...) Ich würde gern eine Function schreiben, welche den NAMEN eines Formulartyps TMyForm1, TMyForm2, usw. als String übergeben bekommt, und die dann aus dem tatsächlich als Klasse definierten TMyForm1 eine Instanz created (die von mir gesuchte Funktion nenne ich mal StrToClass):
Delphi-Quellcode:
In der aufrufenden Procedure könnte ich das dann weiternutzen :
Function FormAufruf (Formtyp: String): TForm;
Begin Result:=StrToClass(FormTyp).Create(Application); end;
Delphi-Quellcode:
Wäre ja quasi ein Pinocchio-Effekt : Aus einem 'hölzernen' String wird ein 'lebendiges' Formular.
Procedure Formbenutzen;
var BenutzForm: TForm; BenutzFormName: String; Begin BenutzFormName:='TMyForm1'; Benutzform:=FormAufruf(BenutzFormName); BenutzForm.Showmodal; BenutzForm.Free; End; Nicht anvisiert ist hier eine CASE-Struktur, die alle vorhandenen TMyForm? abfragt, und in der auch alle vorhandenen Typen vorher eingetragen werden sollen... Hat jemand sowas schon mal gemacht ? Gibts da eine Funktion ? Ist das etwa was triviales, was ich nur einfach nicht kenne ? :stupid: Oder ist es schlicht unmöglich ? :kotz: In der OH oder in DP habe ich mit den dollsten Suchbegriffen nix gefunden.... :| Bin für jeden Tip dankbar, da ich sonst einen MeGa-Case schreiben darf..... Viele Grüsse, ST2000 |
Re: 'TMyForm' nach TMyForm casten ? ("lebendig" we
Trivial ist die Lösung nicht, aber interessant.
Du schreibst eine Klasse, die Dir Formulare zurückgibt. Da sie die Dinger produziert nennen wir sie einfach mal FormFactory. Was die genau macht kommt am Ende. Im Initialization Teil der Unit-Deklaration erzeugst Du eine globale(!) Variable mit der Factory und erzeugst eine Instanz. Im Finalization Teil zerstörst Du sie wieder. Wir programmieren schliesslich ordentlich ;-) Diese Unit (wo die FormFactory drin ist) bindest Du bei allen Formularen ein, die Du zur Laufzeit herzaubern willst. Im Initialization Teil der Units mit den Formularen trägst Du das Formular dann in der Factory ein. Du machst das Formular also sozusagen bei der Factory bekannt. Die Factory selber macht folgendes: Sie hält einen Container von Formularnamen und einen von Forms vor. Ein Formular wird dann z.B. mit:
Delphi-Quellcode:
registriert.
Initialization
FormFactory.RegisterForm('Normales Fenster', TForm); Die Factory nimmt also einen String und ein Objekt vom Typ TForm auf. Da jedes Deiner Formulare von TForm abgeleitet ist ist das kein Problem. Diese Registrierung packt deine Factory dann ins 'Lager'. Wenn Du nun ein Formular haben willst, machst Du folgendes:
Delphi-Quellcode:
Die Factory sucht nun nach dem String, pickt sich die übergebene Klasse heraus (in dem Fall ein TForm) und erzeugt das ganze Ding. z.B. in einem result := m_FormArray[m_NameArray.IndexOf('Normales Fenster')].Create(self);
var Formular: TForm
begin Formular := FormFactory.GetForm('Normales Fenster'); Anstelle dem fixen String halt eine Variable. Da in dem Formarray ja ein Pointer auf die beim Registrieren angegebene Klasse vorliegt und eben kein reguläres TForm kannst Du hierüber alle registrierten Formulare zur Laufzeit anfordern. |
Re: 'TMyForm' nach TMyForm casten ? ("lebendig" we
Hallo Phoenix,
Vielen Dank für das schnelle Feedback. Verstehe ich es denn richtig :
Delphi-Quellcode:
hätte dann die Deklaration
Initialization
FormFactory.RegisterForm('Normales Fenster', TForm);
Delphi-Quellcode:
und ich lege in der FormFactory-Klasse dann das besagte Array m_FormArray[] an, welches ich als array m_FormArray[] of TForm deklariere.
RegisterForm(FormName: String, FormTyp: TForm);
Ist dann zwar auch eine Art Index von MyForm-Typen, die ich aber dann zumindest per Anmeldung bequem eintragen lassen kann.... Klingt gut. Jedenfalls eleganter als ein Endlos-Case. Ist doch richtig : Wenn ich bei 'Normales Fenster' -> TMyForm4711 mit
Delphi-Quellcode:
eine Instanz Result -> MyForm4711 erzeuge und diese als TForm an eine die FormFactory aufrufende Procedure übergebe, kann ich doch in der weiteren Verwendung der Instanz mit TMyForm4711 bzw. den darauf zeigenden Pointer stets zurückcasten ?
result := m_FormArray[m_NameArray.IndexOf('Normales Fenster')].Create(self);
Also :
Delphi-Quellcode:
führt dann eine Methode aus, die es NUR in TMyForm4711 und nicht in TForm gibt ???
TMyForm4711(ErzeugteForm=TForm).MethodeAusTMyForm4711
Im Grunde würde es dann ja reichen, nur den richtigen Pointer für 'Normales Fenster' zu ermitteln, der seinerzeit beim RegisterForm erstellt wurde, und diesen dann in der die FormFactory aufrufenden Procedure zu benutzen, um erst dort das MyForm4711 zu instanzieren. Dann hätte man ausserhalb der FormFactory beides noch verfügbar : Das Form und den Pointer auf TMyForm4711. Aber geht das mit dem Casten so ? TMyForm4711 instanzieren -> als TForm übergeben an aufrufende Procedure -> dort mit TMyForm4711(TForm) casten -> alle individuellen Methoden und Attribute der TMyForm4711 - Klasse weiterbenutzen ? Gruß, ST2000 |
Re: 'TMyForm' nach TMyForm casten ? ("lebendig" we
Ja, prinzipiell geht das schon.
Ich würde aber nie 'hart' casten (also TMyForm4711(Form).blafasel ) sondern immer nur 'weich' : (Form as TMyForm4711).blafasel Das hat den Vorteil, daß Dir der Compiler Fehlermeldungen gibt, wenn Du etwas hast, das sich nicht als TMyForm4711 casten lässt. Was den Pointer angeht: Du kannst ja neben FormFactory.GetForm (das direkt instanziert) noch ein FormFactory.GetClass implementieren, das Dir den Pointer direkt durchreicht. So bist Du imho ein wenig flexibler. Allerdings hab ich bisher für sowas noch keine Anwendung gefunden. |
BTW... woher nehme ich .RegisterForm(...,TForm) ???
Hallo Phoenix,
da fällt mir nun aber noch ein: Um die FormFactory.RegisterForm - Methode auszuführen, also eine Formularklasse anzumelden, brauche ich doch zunächst den Formular-Typen als Übergabeparameter. :| Irgendwo muss ich ja dann eine Routine schreiben, die z.B. bei Programmstart die ganzen Formklassen per .RegisterForm (String,TForm) registriert. :? Kann ich denn irgendwo auslesen, welche "Type TMyForm? = class(Tform)" - Deklarationen vorhanden sind ? :?: Müsste ja im Grunde gehen, denn soweit ich eine Unit mit so einer Klassendeklaration mit uses einbinde, steht der Typ ja für einen create zur Verfügung. Demnach müßte Delphi ja bei Programmstart (oder nur bei Compilestart?) irgendwo einen Index der ganzen gefundenen Type-Statements in den diversen Units erstellen. Wenn ich Create(TMyForm1) anweise, ist TMyForm1 doch strenggenommen nur ein bereits angelegter Zeiger auf eben diesen Typ, richtig ? :gruebel: Weisst Du, wie man das anzapfen kann ? Um die Typen(-Zeiger) durchzuiterieren und in mein FormFactory-Typen-Inventar zu registrieren ? Sonst muss ja doch wieder irgendeine statische Auflistung aller Klassen her. Und es können 70-100 werden... :roteyes: Gruss, ST2000 |
Re: 'TMyForm' nach TMyForm casten ? ("lebendig" we
Hallo jungs...hallo PD!
Was haltet ihr von dieser lösung?
Delphi-Quellcode:
..warum nicht bereits vorhandene möglichkeiten nutzen?
implementation
{$R *.dfm} var f:TForm; procedure TForm1.Button1Click(Sender: TObject); begin f := StrToForm('TForm1'); if f<>nil then f.Show; end; function StrToForm(className:string):TForm; var c:TClass; begin c:=FindClass(className); if (c<>nil) and c.InheritsFrom(TForm) then result := TFormClass(c).Create(nil); end; initialization registerclass(TForm1); end. mfg |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:46 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz