Accediendo a la clase de controlador FXML
Me gustaría comunicarme con una clase de controlador FXML en cualquier momento, para actualizar información en pantalla desde la aplicación principal u otras etapas.
es posible? No he encontrado ninguna manera de hacerlo.
Las funciones estáticas podrían ser una forma, pero no tienen acceso a los controles del formulario.
¿Algunas ideas?
Puede obtener el controlador enFXMLLoader
FXMLLoader fxmlLoader = new FXMLLoader();
Pane p = fxmlLoader.load(getClass().getResource("foo.fxml").openStream());
FooController fooController = (FooController) fxmlLoader.getController();
guárdelo en su escenario principal y proporcione el método getter getFooController().
Desde otras clases o etapas, cada vez que necesites actualizar la página "foo.fxml" cargada, solicítalo desde su controlador:
getFooController().updatePage(strData);
updatePage() puede ser algo como:
// ...
@FXML private Label lblData;
// ...
public void updatePage(String data){
lblData.setText(data);
}
// ...
en la clase FooController.
De esta manera, otros usuarios de la página no se preocupan por la estructura interna de la página, como qué y dónde Label lblData
está.
Mire también https://stackoverflow.com/a/10718683/682495 . En JavaFX 2.2 FXMLLoader
está mejorado.
Solo para ayudar a aclarar la respuesta aceptada y tal vez ahorrar un poco de tiempo a otras personas que son nuevas en JavaFX:
Para una aplicación JavaFX FXML, NetBeans generará automáticamente su método de inicio en la clase principal de la siguiente manera:
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
Ahora, todo lo que necesitamos hacer para tener acceso a la clase de controlador es cambiar el load()
método FXMLLoader de la implementación estática a una implementación instanciada y luego podemos usar el método de la instancia para obtener el controlador, así:
//Static global variable for the controller (where MyController is the name of your controller class
static MyController myControllerHandle;
@Override
public void start(Stage stage) throws Exception {
//Set up instance instead of using static load() method
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
Parent root = loader.load();
//Now we have access to getController() through the instance... don't forget the type cast
myControllerHandle = (MyController)loader.getController();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
Otra solución es configurar el controlador desde su clase de controlador, así...
public class Controller implements javafx.fxml.Initializable {
@Override
public void initialize(URL location, ResourceBundle resources) {
// Implementing the Initializable interface means that this method
// will be called when the controller instance is created
App.setController(this);
}
}
Esta es la solución que prefiero usar ya que el código es algo complicado para crear una instancia de FXMLLoader completamente funcional que maneje adecuadamente los recursos locales, etc.
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/sample.fxml"));
}
versus
@Override
public void start(Stage stage) throws Exception {
URL location = getClass().getResource("/sample.fxml");
FXMLLoader loader = createFXMLLoader(location);
Parent root = loader.load(location.openStream());
}
public FXMLLoader createFXMLLoader(URL location) {
return new FXMLLoader(location, null, new JavaFXBuilderFactory(), null, Charset.forName(FXMLLoader.DEFAULT_CHARSET_NAME));
}
Al cargar el objeto desde la pantalla principal, una forma de pasar datos que encontré y que funciona es usar la búsqueda y luego configurar los datos dentro de una etiqueta invisible que puedo recuperar más tarde desde la clase del controlador. Como esto:
Parent root = FXMLLoader.load(me.getClass().getResource("Form.fxml"));
Label lblData = (Label) root.lookup("#lblData");
if (lblData!=null) lblData.setText(strData);
Esto funciona, pero debe haber una manera mejor.