JavaFX FXML-Controller - Konstruktor vs Initialisierungsmethode

84

Meine ApplicationKlasse sieht so aus:

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);
    }
}

Das FXMLLoadererstellt eine Instanz des entsprechenden Controllers (in der FXMLDatei über angegeben fx:controller), indem zuerst der Standardkonstruktor und dann die initializeMethode aufgerufen werden:

public class MainViewController {

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

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

Die Ausgabe ist:

first
second

Warum gibt es die initializeMethode? Was ist der Unterschied zwischen der Verwendung eines Konstruktors oder der initializeMethode zum Initialisieren der für den Controller erforderlichen Dinge?

Vielen Dank für Ihre Vorschläge!

mrbela
quelle

Antworten:

124

In wenigen Worten: Der Konstruktor wird zuerst aufgerufen, dann werden alle mit @FXMLAnmerkungen versehenen Felder ausgefüllt und dann initialize()aufgerufen. Der Konstruktor hat also @FXMLKEINEN Zugriff auf Felder, die auf in der .fxml-Datei definierte Komponenten verweisen, während er initialize()Zugriff auf diese hat.

Zitat aus der Einführung in FXML :

[...] Der Controller kann eine initialize () -Methode definieren, die auf einem implementierenden Controller einmal aufgerufen wird, wenn der Inhalt des zugehörigen Dokuments vollständig geladen wurde. [...] Dadurch kann die implementierende Klasse jeden erforderlichen Beitrag ausführen -Verarbeitung des Inhalts.

Nikos Paraskevopoulos
quelle
2
Ich verstehe nicht. Die Art, wie er es tut, ist vorbei FXMLLoader, richtig? Ich sehe also keinen Vorteil darin, auf die initialize()- Methode zu warten . Sobald die FXML geladen ist, hat der folgende Code Zugriff auf die @FXMLVariablen. Sicher, er macht es in der Startmethode und nicht im Konstruktor, würde aber initialize()in seinem Fall irgendeinen Nutzen bringen?
Codepleb
90

Die initializeMethode wird aufgerufen, nachdem alle mit @FXMLAnmerkungen versehenen Elemente eingefügt wurden. Angenommen, Sie haben eine Tabellenansicht, die Sie mit Daten füllen möchten:

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. 
    }
}
Itai
quelle
11

Zusätzlich zu den obigen Antworten sollte wahrscheinlich angemerkt werden, dass es einen alten Weg gibt, die Initialisierung zu implementieren. Es gibt eine Schnittstelle namens Initializable aus der fxml-Bibliothek.

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());
    }
}

Parameter:

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. 

Und der Hinweis in den Dokumenten, warum die einfache Verwendung @FXML public void initialize()funktioniert:

NOTEDiese Schnittstelle wurde durch die automatische Injektion von Standort- und Ressourceneigenschaften in die Steuerung ersetzt. FXMLLoader ruft nun automatisch alle vom Controller definierten, entsprechend kommentierten no-arg initialize () -Methoden auf. Es wird empfohlen, nach Möglichkeit den Injektionsansatz zu verwenden.

gkhaos
quelle