Hallo die Gemeinde,
ich habe in einem Projekt eine ganze Latte an Klasse zu registrieren:
registerclass(TFrmxyz...)
Nun meine Frage: kann man dieses über Variablen steuern?
Ich würde die Klassen gern aus einer
DB als "Liste" einlesen, weil immer nur die Formulare generiert werden, die für diesen User zugelassen sind.
Am liebsten würde ich mit der Uses-Klausel ähnlich verfahren, aber ich glaube, das ist nicht möglich?
Beste Grüsse
mcinternet
Was Du aus der Datenbank holen kannst sind die Namen der Klassen als String, nicht war? Was Du dann brauchst ist eine Methode, um aus diesem String eine Referenz auf die Klasse (zur Laufzeit) zu erzeugen. Das sollte mit Hilfe von extended
RTTI möglich sein.
Delphi-Quellcode:
procedure TForm1.RunTest;
var
LContext : TRttiContext;
LType : TRttiType;
begin
LContext := TRttiContext.Create;
try
LType := LContext.FindType(self.QualifiedClassName);
if LType.IsInstance then
memo1.lines.Add('Found: '+LType.QualifiedName)
else
memo1.lines.Add(Classname + ' not found');
finally
LContext.Free;
end;
end;
Das Problem ist hier, dass FindType einen "qualified name" erwartet, d.h. eine Kombination aus
Unit und Klassennamen, separiert durch einen Punkt. Wenn Du also in der Datenbank nur die Klassennamen abgelegt hast wird es etwas aufweniger. Dann mußt Du über TRttiContext.GetTypes die Liste aller bekannten Typen holen (und das sind Tausende!) und Dir die benötigten selbst in der Liste suchen. Nicht gerade flott, aber das machst Du ja nur einmal, beim Start der Anwendung.
Ansonsten gibt es noch die self-made Lösung: Bau deine eigene Klassenliste (basierend auf TClasslist oder TList<TClass>). Das wäre ein Singleton-Object, in das jede Formunit in der Initialisation-Sektion ihre Formklasse registriert. Dann brauchst Du später nur noch in dieser Liste suchen.
Was Du aber nicht vermeiden kannst, ist alle Forms (um die geht es ja wohl hier) auch in die Anwendung einzubinden, egal ob sie später gebraucht werden oder nicht.
Rtti wird halt nur für Typen erzeugt, die auch einkompiliert werden, und das gleiche gilt für
Unit-Initialisations.
Wenn Du wirklich auch nur ausliefern willst was der Kunde verwenden darf brauchts Du ein anderes Design der Anwendung. In diesem Fall muss die Anwendung auf Packages basieren, wobei kundenspezifische Teile der Anwendung in eigenen Packages untergebracht werden, die dann zur Laufzeit dynamisch geladen werden. Wenn Du bisher kein solches Design verwendet hast und die Anwendung praktisch schon existiert ist die Umarbeitung ein erheblicher Aufwand, und auch die Auslieferung wird komplexer, da Du jede Menge Packages (
RTL,
VCL, 3rd-party) mit installieren musst. Packages sind all or nothing, und da jede
Unit nur in einer der Packages vorkommen darf erfordert die Aufteilung existierenden Kodes eine Menge Planung und Vorarbeit, besonders bei schlampig gebauten
RAD-Anwendungen mit vielen wechselseitigen Abhängigkeiten zwischen Units.