Controlador JavaFX FXML - constructor vs método de inicialización


84

Mi Applicationclase se ve así:

public class Test extends Application {

    private static Logger logger = LogManager.getRootLogger();

    @Override
    public void start(Stage primaryStage) throws Exception {

        String resourcePath = "/resources/fxml/MainView.fxml";
        URL location = getClass().getResource(resourcePath);
        FXMLLoader fxmlLoader = new FXMLLoader(location);

        Scene scene = new Scene(fxmlLoader.load(), 500, 500);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

El FXMLLoadercrea una instancia del controlador correspondiente (dado en el FXMLarchivo a través de fx:controller) invocando primero el constructor predeterminado y luego el initializemétodo:

public class MainViewController {

    public MainViewController() {
        System.out.println("first");
    }

    @FXML
    public void initialize() {
        System.out.println("second");
    }
}

La salida es:

first
second

Entonces, ¿por qué existe el initializemétodo? ¿Cuál es la diferencia entre usar un constructor o el initializemétodo para inicializar las cosas requeridas por el controlador?

¡Gracias por tus sugerencias!

Respuestas:


124

En pocas palabras: primero se llama al constructor, luego @FXMLse rellenan los campos anotados y luego initialize()se llama. Por lo tanto, el constructor NO tiene acceso a los @FXMLcampos que se refieren a los componentes definidos en el archivo .fxml, mientras que initialize()sí tiene acceso a ellos.

Citando de la Introducción a FXML :

[...] el controlador puede definir un método initialize (), que se llamará una vez en un controlador de implementación cuando el contenido de su documento asociado se haya cargado por completo [...] Esto permite que la clase de implementación realice cualquier publicación necesaria -procesamiento del contenido.


2
No entiendo. La forma en que lo hace ha terminado FXMLLoader, ¿verdad? Así que no veo ningún beneficio en esperar el initialize()método -. Tan pronto como se carga el FXML, el siguiente código tiene acceso a las @FXMLvariables. Claro, lo hace en el método de inicio y no en el constructor, pero ¿ initialize()aportaría algún beneficio en su caso?
codepleb

90

El initializemétodo se llama después de que @FXMLse hayan inyectado todos los miembros anotados. Suponga que tiene una vista de tabla que desea completar con datos:

class MyController { 
    @FXML
    TableView<MyModel> tableView; 

    public MyController() {
        tableView.getItems().addAll(getDataFromSource()); // results in NullPointerException, as tableView is null at this point. 
    }

    @FXML
    public void initialize() {
        tableView.getItems().addAll(getDataFromSource()); // Perfectly Ok here, as FXMLLoader already populated all @FXML annotated members. 
    }
}

11

Además de las respuestas anteriores, probablemente debería tenerse en cuenta que existe una forma heredada de implementar la inicialización. Hay una interfaz llamada Initializable de la biblioteca fxml.

import javafx.fxml.Initializable;

class MyController implements Initializable {
    @FXML private TableView<MyModel> tableView;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        tableView.getItems().addAll(getDataFromSource());
    }
}

Parámetros:

location - The location used to resolve relative paths for the root object, or null if the location is not known.
resources - The resources used to localize the root object, or null if the root object was not localized. 

Y la nota de los documentos por qué funciona la forma simple de usar @FXML public void initialize():

NOTEEsta interfaz ha sido reemplazada por la inyección automática de propiedades de ubicación y recursos en el controlador. FXMLLoader ahora llamará automáticamente a cualquier método initialize () no-arg adecuadamente anotado definido por el controlador. Se recomienda que se utilice el método de inyección siempre que sea posible.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.