Kannst Du etwas genauer sagen, was Du machen willst? Das, was Du schreibst, ist etwas verwirrend.
Was ich da heraus höre: Du hast vermutlich irgend ein Framework, welches im Rahmen der Instanz-Erzeugung dann vermutlich eine initialize Methode aufrufen kann. Und dabei geht es um einen Controller.
Das kann prinzipiell vieles sein. Wenn ich raten müsste, dann tippe ich auf JavaFX und den FXMLLoader. Der FXMLLoader erzeugt eine Instanz vom im FXML angegebenen Controller. Da kann man erst einmal nicht direkt etwas an Parametern übergeben. Hier gibt es aber zwei Möglichkeiten, wie man vorgehen kann:
1) FXMLLoader.setController: Du erzeugst eine Instanz von FXMLLoader, setzt den Controller und dann lädst Du per load das fxml File.
2) Du kannst beim load auch eine controllerFactory übergeben. Das ist dann ein Callback, welches der FXMLLoader dann nutzt, um eine Instanz zu erzeugen. Statt als Parameter bei dem load Aufruf kann man auch eine Instanz von FXMLLoader erzeugen und setControllerFactory vor dem load nutzen.
Beide Methoden haben aber das Problem, dass Du damit im Code den Controller vorgibst und Du nicht mehr die Deklaration im FXML nutzt.
3) Was man aber auch machen könnte, wäre den Ablauf etwas abzuändern:
Die Daten werden in der Scene oder Stage als UserData gesetzt (setUserData).
Dann kann man in der initialize Methode einen Handler setzen, der die UserData Daten auswertet, sobald die Scene oder Stage gesetzt wird (Listener auf der sceneProperty. Wenn die Daten in der Stage sind, dann muss man bei der neuen Scene erst die Stage holen (getRoot())).
Das ist der Weg, den ich als zielführend ansehe, wenn es um begrenzte Daten geht ... also z.B. einer Art Model für den Controller. Also genau eine Instanz einer Klasse, die da dann benötigt wird.
4) Wenn es ein spezifisches Control gibt, das mit Daten gefüllt werden muss, dann kann man prinzipiell auch eine BuilderFactory verwenden. Das ist aber dann auch ein relativ spezielles Anforderungs-Szenario ...
Aber natürlich lässt sich sowas auch noch relativ gut ausbauen. Es ist denkbar, eine ControllerFactory zu bauen, die eine KonstruktorInjection durchführt.
Wir wollen eine ControllerFactory, die ein gewisses Wissen hat (Also Dinge, die injected werden können) und wenn dann eine Klasse als Controller angefordert wird, dann wird per Reflection geschaut:
Alle Konstruktoren werden durchgegangen und es wird geprüft, ob alle Parameter bedient werden können
wird so ein Konstruktor gefunden, wird dieser aufgerufen und die Instanz zurück gegeben
Wird kein passender Konstruktor gefunden, dann wird eine Fehlermeldung ausgegeben
Sowas mal eben schnell per ChatGPT schreiben lassen:
Java:
importjavafx.util.Callback;importjava.lang.reflect.Constructor;importjava.util.Map;importjava.util.Optional;importjava.util.stream.Stream;publicclassUniversalControllerFactoryimplementsCallback<Class<?>,Object>{privatefinalMap<Class<?>,Object> parameterMap;publicUniversalControllerFactory(Map<Class<?>,Object> parameterMap){this.parameterMap = parameterMap;}@OverridepublicObjectcall(Class<?> controllerClass){try{Optional<Constructor<?>> bestConstructor =Stream.of(controllerClass.getConstructors()).filter(constructor ->canBeInstantiated(constructor, parameterMap)).findFirst();if(bestConstructor.isPresent()){Constructor<?> constructor = bestConstructor.get();Object[] parameters =Stream.of(constructor.getParameterTypes()).map(parameterMap::get).toArray();return constructor.newInstance(parameters);}else{thrownewIllegalStateException("Kein passender Konstruktor gefunden für "+ controllerClass.getName());}}catch(Exception e){thrownewRuntimeException("Fehler beim Erstellen der Controller-Instanz für "+ controllerClass.getName(), e);}}privatebooleancanBeInstantiated(Constructor<?> constructor,Map<Class<?>,Object> parameterMap){returnStream.of(constructor.getParameterTypes()).allMatch(parameterMap::containsKey);}}
Das Ganze kann man noch etwas ausbauen. Dazu könnte man z.B. schauen, was so die typischen Injection Libraries so bieten. Das ist aber jetzt erst einmal aussen vor würde ich sagen.
Die Idee gefällt mir aber. Gibt es da schon eine kleine Library? Ansonsten wäre da eine InjectionFX Library denkbar, die schnell geschrieben ist. Ggf. mit etwas mehr Features. Die Idee wäre bei einer UI, dass man so in den Controller problemlos Dinge Injecten kann.
Zusätzliche Features wären dann ggf. sowas wie Annotations auf Klassen a.la. @Component oder so. Die müsste man dann nicht explizit angeben. Und man hätte einen FXMLInjectionLoader oder so...
Ja, es handelt sich um JavaFX. Ich hab eine zweite Controller-Datei (und eine zweite Hello-View-Datei. Von der zweiten HelloController-Datei aus starte ich ein Fenster, das die 3 Zahlen mit Textfields erfragt. Auf dem Fenster ist auch ein Startbutton, der die Scene von dem ersten Controller startet. Dann verknüpfe ich an einer Stelle die beiden Controller und rufe die Methode setNumbers auf. Die muss ich im ersten Controller auch aufrufen und vor allem deklarieren. Aber hier ist meine Initializable-Methode schneller. Mein Ausbilder meinte, ich soll versuchen, die SetNumbers-Methode vorher auszuführen und durch googeln habe ich dann rausgefunden, dass man dem Konstruktor die Zahlen auch übergeben kann als Parameter. Das erste HelloController, das erste Fenster braucht die 3 Zahlen für ein Spiel, das hier läuft.
Also bei so Abhängigkeiten ist es aus meiner Sicht besser, nicht auf dem Standard initialize zu setzen sondern es individuell zu machen.
Du kannst einen Controller bauen, der etwas in der Form macht:
Java:
publicclassMyController{privateboolean isInitialized =false;publicvoidinitialize(WhateverClass data){// Do the initialization required with data
isInitialized =true;}}
Das isInitialized kannst Du auch nutzen, wenn Du bei Events aufpassen willst, ob die Initialisierung bereits erfolgt ist.
Das void initialize(WhateverClass) kannst Du auch in einem Interface definieren. Dann wäre eine Laden eines FXML Dokuments etwas wie:
(Wenn MyInitializableControler entweder das Interface oder der konkrete Controller ist.)
Sprich: Statt die Initialisierung in Controller zu packen verschiebst Du die eigentliche Initialisierung nach hinten. Das wäre eine einfache Alternative.
Das ist sehr lieb, aber ich fürchte, mein Ausbilder besteht darauf, dass ich den Konstruktor mit den Parametern fülle, die ich übergeben will. Ich glaube, dann ist das mit der Controller-Factory im Zweifel die bessere Lösung, danke dafür!
Ok, nach meinem Verständnis ist das auch eine sehr einfache Vorgehensweise - nur eben mit dem bereits beschriebenen Problem, dass Du im Code dann auch die richtige Klasse laden musst, was dem deklarativen Ansatz etwas widerspricht.
Und falls Du das noch nicht ganz erarbeitet haben solltest: Bei dem Ansatz kann das Laden dann so aussehen:
Natürlich ist es notwendig, die Ressource, den Klassenname des Controllers und die notwendigen Parameter anzupassen. Und in der FXML muss dann natürlich auch der Controller (in meinem Beispiel MyController) als fx:controller aufgeführt werden.
Ich habe ansonsten - falls es jemanden interessiert (lass Dich davon nicht verwirren @Anfaengerin! Evtl. einfach ignorieren!) - unter https://github.com/kneitzel/injectFX mal versucht, so einen ersten Ansatz für ein automatisches Injecten zu bauen. Ist aber nur eine kleine Spielerei, die ich gestern Abend mal schnell gemacht habe. Ist halt noch nicht abgeschlossen, aber zum einen habe ich da die Klasse InjectingControllerFactory, die standalone genutzt werden kann. Und ansonsten dreht sich da vieles um automatisches Injecten von Komponenten, die mit @FXMLComponet markiert wurden...