Approccio raccomandato
Questa risposta elenca diversi meccanismi per il passaggio dei parametri ai controller FXML.
Per le piccole applicazioni consiglio vivamente di passare i parametri direttamente dal chiamante al controller: è semplice, diretto e non richiede framework aggiuntivi.
Per applicazioni più grandi e complicate, varrebbe la pena indagare se si desidera utilizzare i meccanismi di iniezione di dipendenza o bus di eventi all'interno dell'applicazione.
Passare i parametri direttamente dal chiamante al controller
Passare i dati personalizzati a un controller FXML recuperando il controller dall'istanza del caricatore FXML e chiamando un metodo sul controller per inizializzarlo con i valori dei dati richiesti.
Qualcosa come il seguente codice:
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());
}
}
Un nuovo FXMLLoader è costruito come mostrato nel codice di esempio ie new FXMLLoader(location)
. La posizione è un URL e puoi generare tale URL da una risorsa FXML:
new FXMLLoader(getClass().getResource("sample.fxml"));
Fare attenzione a NON utilizzare una funzione di caricamento statico su FXMLLoader, altrimenti non sarà possibile ottenere il controller dall'istanza del caricatore.
Le stesse istanze di FXMLLoader non sanno mai nulla sugli oggetti di dominio. Non passi direttamente oggetti di dominio specifici dell'applicazione nel costruttore FXMLLoader, invece:
- Costruisci un FXMLLoader basato sul markup fxml in una posizione specificata
- Ottieni un controller dall'istanza FXMLLoader.
- Richiamare i metodi sul controller recuperato per fornire al controller riferimenti agli oggetti del dominio.
Questo blog (da un altro scrittore) fornisce un supplente, ma simile, ad esempio .
Impostazione di un controller sul FXMLLoader
CustomerDialogController dialogController =
new CustomerDialogController(param1, param2);
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"customerDialog.fxml"
)
);
loader.setController(dialogController);
Pane mainPane = (Pane) loader.load();
È possibile costruire un nuovo controller nel codice, passando tutti i parametri desiderati dal chiamante al costruttore del controller. Dopo aver creato un controller, è possibile impostarlo su un'istanza FXMLLoader prima di richiamare il metodo load()
dell'istanza .
Per impostare un controller su un caricatore (in JavaFX 2.x) NON PUOI fx:controller
nemmeno definire un attributo nel tuo file fxml.
A causa della limitazione della fx:controller
definizione in FXML, personalmente preferisco ottenere il controller da FXMLLoader piuttosto che impostare il controller in FXMLLoader.
Avere il controller recuperare i parametri da un metodo statico esterno
Questo metodo è esemplificato dalla risposta di Sergey a Javafx 2.0 How-to Application.getParameters () in un file Controller.java .
Usa iniezione di dipendenza
FXMLLoader supporta i sistemi di iniezione di dipendenza come Guice, Spring o Java EE CDI consentendo di impostare una fabbrica di controller personalizzati su FXMLLoader. Ciò fornisce un callback che è possibile utilizzare per creare l'istanza del controller con valori dipendenti iniettati dal rispettivo sistema di iniezione delle dipendenze.
Un esempio di iniezione di dipendenza da controller e applicazione JavaFX con Spring è fornito nella risposta a:
Un approccio di iniezione di dipendenza davvero piacevole e pulito è esemplificato dal framework afterburner.fx con un'applicazione air-hack di esempio che lo utilizza. afterburner.fx si affida a JEE6 javax.inject per eseguire l'iniezione di dipendenza.
Usa un bus eventi
Greg Brown, il creatore e implementatore della specifica FXML originale, suggerisce spesso di prendere in considerazione l'uso di un bus di eventi, come Guava EventBus , per la comunicazione tra controller istanziati FXML e altre logiche applicative.
EventBus è un'API di pubblicazione / sottoscrizione semplice ma potente con annotazioni che consente ai POJO di comunicare tra loro ovunque in una JVM senza dover fare riferimento l'uno all'altro.
Domande e risposte di follow-up
sul primo metodo, perché restituisci Stage? Il metodo può essere nullo anche perché stai già dando il comando show (); appena prima della fase di ritorno ;. Come si pianifica l'utilizzo restituendo lo stage
È una soluzione funzionale a un problema. Uno stage viene restituito dalla showCustomerDialog
funzione in modo che un riferimento ad esso possa essere memorizzato da una classe esterna che potrebbe voler fare qualcosa, come nascondere lo stage in base a un clic del pulsante nella finestra principale, in un secondo momento. Una soluzione alternativa orientata agli oggetti potrebbe incapsulare la funzionalità e il riferimento dello stage all'interno di un oggetto CustomerDialog o far estendere lo stage a CustomerDialog. Un esempio completo di un'interfaccia orientata agli oggetti a una finestra di dialogo personalizzata che incapsula FXML, i controller e i dati del modello va oltre lo scopo di questa risposta, ma può rendere utile un post sul blog per chiunque sia incline a crearne uno.
Informazioni aggiuntive fornite dall'utente StackOverflow chiamato @dzim
Esempio di Spring Boot Dependency Injection
Alla domanda su come farlo "The Spring Boot Way", c'è stata una discussione su JavaFX 2, a cui ho risposto nel permalink allegato. L'approccio è ancora valido e testato a marzo 2016, su Spring Boot v1.3.3.RELEASE:
https://stackoverflow.com/a/36310391/1281217
A volte, potresti voler restituire i risultati al chiamante, nel qual caso puoi controllare la risposta alla domanda correlata: