Empfohlener Ansatz
Diese Antwort listet verschiedene Mechanismen zum Übergeben von Parametern an FXML-Controller auf.
Für kleine Anwendungen empfehle ich dringend, Parameter direkt vom Aufrufer an die Steuerung zu übergeben - es ist einfach, unkompliziert und erfordert keine zusätzlichen Frameworks.
Für größere, kompliziertere Anwendungen lohnt es sich zu untersuchen, ob Sie in Ihrer Anwendung Abhängigkeitsinjektions- oder Ereignisbusmechanismen verwenden möchten .
Parameter direkt vom Anrufer an den Controller übergeben
Übergeben Sie benutzerdefinierte Daten an einen FXML-Controller, indem Sie den Controller aus der FXML-Loader-Instanz abrufen und eine Methode auf dem Controller aufrufen, um ihn mit den erforderlichen Datenwerten zu initialisieren.
So etwas wie der folgende Code:
public Stage showCustomerDialog(Customer customer) {
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"customerDialog.fxml"
)
);
Stage stage = new Stage(StageStyle.DECORATED);
stage.setScene(
new Scene(
(Pane) loader.load()
)
);
CustomerDialogController controller =
loader.<CustomerDialogController>getController();
controller.initData(customer);
stage.show();
return stage;
}
...
class CustomerDialogController {
@FXML private Label customerName;
void initialize() {}
void initData(Customer customer) {
customerName.setText(customer.getName());
}
}
Ein neuer FXMLLoader wird wie im Beispielcode gezeigt erstellt, d new FXMLLoader(location)
. H. Der Speicherort ist eine URL, und Sie können eine solche URL aus einer FXML-Ressource generieren, indem Sie:
new FXMLLoader(getClass().getResource("sample.fxml"));
Achten Sie darauf, KEINE statische Ladefunktion für den FXMLLoader zu verwenden, da Sie sonst Ihren Controller nicht von Ihrer Loader-Instanz abrufen können.
FXMLLoader-Instanzen selbst wissen nie etwas über Domänenobjekte. Sie übergeben anwendungsspezifische Domänenobjekte nicht direkt an den FXMLLoader-Konstruktor, sondern:
- Erstellen Sie einen FXMLLoader basierend auf dem fxml-Markup an einem bestimmten Speicherort
- Holen Sie sich einen Controller von der FXMLLoader-Instanz.
- Rufen Sie Methoden auf dem abgerufenen Controller auf, um dem Controller Verweise auf die Domänenobjekte bereitzustellen.
Dieser Blog (von einem anderen Autor) bietet ein alternatives, aber ähnliches Beispiel .
Festlegen eines Controllers im FXMLLoader
CustomerDialogController dialogController =
new CustomerDialogController(param1, param2);
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"customerDialog.fxml"
)
);
loader.setController(dialogController);
Pane mainPane = (Pane) loader.load();
Sie können einen neuen Controller im Code erstellen und alle gewünschten Parameter von Ihrem Aufrufer an den Controller-Konstruktor übergeben. Nachdem Sie einen Controller erstellt haben, können Sie ihn für eine FXMLLoader-Instanz festlegen, bevor Sie die load()
Instanzmethode aufrufen .
Um einen Controller auf einem Loader (in JavaFX 2.x) festzulegen, können Sie NICHT auch ein fx:controller
Attribut in Ihrer fxml-Datei definieren.
Aufgrund der Einschränkung der fx:controller
Definition in FXML ziehe ich es persönlich vor, den Controller vom FXMLLoader zu beziehen, anstatt den Controller in den FXMLLoader zu setzen.
Lassen Sie den Controller Parameter von einer externen statischen Methode abrufen
Diese Methode wird durch die Antwort von Sergey auf Javafx 2.0 How-to Application.getParameters () in einer Controller.java-Datei veranschaulicht .
Verwenden Sie die Abhängigkeitsinjektion
FXMLLoader unterstützt Abhängigkeitsinjektionssysteme wie Guice, Spring oder Java EE CDI, indem Sie eine benutzerdefinierte Controller-Factory auf dem FXMLLoader festlegen können. Dies bietet einen Rückruf, mit dem Sie die Controller-Instanz mit abhängigen Werten erstellen können, die vom jeweiligen Abhängigkeitsinjektionssystem eingespeist werden.
Ein Beispiel für die Injektion von JavaFX-Anwendungen und Controller-Abhängigkeiten mit Spring finden Sie in der Antwort auf:
Ein wirklich netter, sauberer Ansatz zur Abhängigkeitsinjektion wird durch das afterburner.fx-Framework mit einer Beispielanwendung für Air-Hacks veranschaulicht , die es verwendet. afterburner.fx verwendet JEE6 javax.inject , um die Abhängigkeitsinjektion durchzuführen.
Verwenden Sie einen Ereignisbus
Greg Brown, der ursprüngliche Ersteller und Implementierer von FXML-Spezifikationen, schlägt häufig vor, die Verwendung eines Ereignisbusses wie des Guava EventBus für die Kommunikation zwischen FXML-instanziierten Controllern und anderer Anwendungslogik in Betracht zu ziehen .
Der EventBus ist eine einfache, aber leistungsstarke Publish / Subscribe-API mit Anmerkungen, mit der POJOs überall in einer JVM miteinander kommunizieren können, ohne aufeinander verweisen zu müssen.
Follow-up-Fragen und Antworten
Warum geben Sie bei der ersten Methode Stage zurück? Die Methode kann auch ungültig sein, da Sie bereits den Befehl show () eingeben. kurz vor der Rückkehr;. Wie planen Sie die Nutzung, indem Sie die Bühne zurückgeben?
Es ist eine funktionale Lösung für ein Problem. Eine Stufe wird von der showCustomerDialog
Funktion zurückgegeben, damit ein Verweis darauf von einer externen Klasse gespeichert werden kann, die möglicherweise etwas tun möchte, z. B. die Stufe zu einem späteren Zeitpunkt durch Klicken auf eine Schaltfläche im Hauptfenster ausblenden. Eine alternative, objektorientierte Lösung könnte die Funktionalität und die Bühnenreferenz in einem CustomerDialog-Objekt kapseln oder eine CustomerDialog-Erweiterungsstufe haben. Ein vollständiges Beispiel für eine objektorientierte Schnittstelle zu einem benutzerdefinierten Dialogfeld, das FXML-, Controller- und Modelldaten enthält, würde den Rahmen dieser Antwort sprengen, kann jedoch für jeden, der dazu neigt, einen zu erstellen, einen lohnenden Blog-Beitrag darstellen.
Zusätzliche Informationen vom StackOverflow-Benutzer @dzim
Beispiel für Spring Boot Dependency Injection
Bei der Frage, wie es geht "The Spring Boot Way", gab es eine Diskussion über JavaFX 2, die ich im angehängten Permalink beantwortet habe. Der Ansatz ist noch gültig und wurde im März 2016 auf Spring Boot v1.3.3.RELEASE getestet:
https://stackoverflow.com/a/36310391/1281217
Manchmal möchten Sie die Ergebnisse möglicherweise an den Anrufer zurückgeben. In diesem Fall können Sie die Antwort auf die entsprechende Frage überprüfen: