ventanas ventana una tutorial secundarias paso manejo makery español desde code botones boton abrir javafx fxml

ventana - Javafx: ¿puede la clase de aplicación ser la clase de controlador?



javafx ventanas secundarias (2)

El comportamiento predeterminado de FXMLLoader es crear una nueva instancia de la clase de controlador y usar esa instancia como controlador.

Específicamente, FXMLLoader hace algo como:

  • Lea el elemento raíz FXML.
    • Si el elemento raíz FXML tiene un atributo fx:controller , entonces
      • Si ya existe un controlador, inicie una excepción; de lo contrario, cree una instancia de la clase 1 especificada y configúrela como controlador
  • Continúa analizando el archivo FXML. Si los elementos tienen un atributo fx:id y existe un controlador (por cualquier mecanismo), inyecte esos campos en el controlador. Del mismo modo, registre los controladores de eventos como llamadas a métodos en la instancia del controlador.
  • Invoque initialize() en el controlador, si existe un controlador y tiene dicho método.

Entonces, la pregunta que hiciste:

¿Puede la clase de aplicación ser la clase de controlador?

Sí, pero probablemente sea una idea terrible. Si simplemente especifica la subclase de Application como la clase de controlador utilizando fx:controller , se crea una segunda instancia de la subclase de Application , se inyectan campos @FXML @FXML en esa segunda instancia y se invoca el método initialize() en esa segunda ejemplo. Obviamente, los @FXML @FXML nunca se inicializan en la instancia en la que se invoca start(...) , y el método initialize() nunca se invoca en esa instancia.

La pregunta que probablemente quisiste decir es:

¿Se puede usar la instancia de clase de aplicación creada en el lanzamiento como controlador?

La respuesta a esto también es sí, y, aparte de los programas de demostración muy pequeños que tiene la intención de descartar de inmediato, también es probablemente una muy mala idea. Harías esto por

public class MyApp extends Application { @FXML private Node someNode ; public void initialize() { // do something with someNode } @Override public void start(Stage primaryStage) throws Exception { FXMLLoader loader = new FXMLLoader(getClass().getResource("/path/to/fxml/file.fxml")); loader.setController(this); Parent root = loader.load(); primaryStage.setScene(new Scene(root)); primaryStage.show(); } }

Tenga en cuenta que para usar este código, su archivo FXML no debe tener un atributo fx:controller .

El problema con esto es que no tienes separación ni flexibilidad. (Por ejemplo, si crea una segunda instancia de la vista definida en su archivo FXML en algún lugar, terminará con una segunda instancia de subclase de Application , que en el mejor de los casos es contraintuitiva (una aplicación con dos instancias de Application ...)).

Así que recomendaría usar una clase separada para el controlador básicamente en todos los casos. La subclase de la Application debe contener un código mínimo y debe usarse solo para iniciar la aplicación.

1 Este paso es en realidad un poco más complejo. Si se especifica una clase en el atributo fx:controller y ya no existe ningún controlador, FXMLLoader busca un controllerFactory . Si existe, el controlador se establece como resultado de pasar la Class especificada al método call() controllerFactory ; de lo contrario, se crea llamando a newInstance() en la clase especificada (efectivamente llamando a su constructor sin argumentos).

Actualmente me estoy enseñando JavaFX, y he tomado un programa de ejemplo simple que codifica la vista y lo estoy convirtiendo en uno que usa FXML (principalmente para poder usar SceneBuilder para construir interfaces de usuario). En lugar de escribir una clase de controlador separada, estoy usando la clase de aplicación (por lo que hay 1 archivo Java y 1 archivo FXML). No estoy usando un método initialize() ya que es un flujo lineal (muestra la interfaz de usuario, llena los campos, espera la entrada). Aparece la vista, pero luego la aplicación falla, ya que ninguno de los controles está asignado a las variables apropiadas (por lo que para la @FXML TableView<...> table , la table es null ).

Sin embargo, puse un método initialize() para la depuración, los controles se inyectan durante initialize() , y luego vuelvo a nulo cuando sale initialize() .

Entonces la pregunta es, ¿JavaFX crea una instancia nueva de la clase de aplicación como una clase de controlador separada? Esto explicaría por qué las variables están fuera de alcance. ¿O es algo más (por ejemplo, los controles se inyectan solo cuando se les devuelve la llamada desde acciones JavaFX)?


Si ha definido que su clase de aplicación sea el controlador en el archivo FXML, JavaFX, si no recuerdo mal, creará una nueva instancia de su clase de aplicación y utilizará la nueva instancia como controlador. Por lo tanto, su clase de aplicación existente todavía tiene nulo para la tabla.

Sin embargo, puede definir el controlador mediante programación en su clase de aplicación para usar su propia instancia:

FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("example.fxml")); fxmlLoader.setController(this); Parent root = (Parent)fxmlLoader.load();