Контролер JavaFX FXML - конструктор проти методу ініціалізації


85

Мій Applicationклас виглядає так:

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

FXMLLoaderСтворює екземпляр відповідного контролера (заданий в FXMLфайлі через fx:controller), викликаючи перший конструктор за замовчуванням , а потім initializeметод:

public class MainViewController {

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

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

Вихід:

first
second

Отже, чому initializeметод існує? У чому різниця між використанням конструктора або initializeметоду для ініціалізації контролером необхідних речей?

Дякуємо за ваші пропозиції!

Відповіді:


125

Кілька слів: спочатку викликається конструктор, потім @FXMLзаповнюються будь-які анотовані поля, потім initialize()викликається.

Це означає , що конструктор робить НЕ має доступу до @FXMLполях , що належать до компонентів , певним в файлі .fxml, в той час як initialize() робить доступ до них.

Посилання з Вступу до FXML :

[...] контролер може визначити метод initialize (), який буде викликаний один раз на контролері-реалізаторі, коли вміст пов'язаного з ним документа буде повністю завантажений [...] Це дозволяє виконуючому класу виконувати будь-які необхідні повідомлення -обробка вмісту.


2
Я не розумію. Те, як він це робить, закінчується FXMLLoader, так? Тому я не бачу користі в очікуванні initialize()методу. Як тільки FXML завантажується, наступний код має доступ до @FXMLзмінних. Звичайно, він робить це в методі запуску, а не в конструкторі, але чи initialize()принесе користь у його випадку?
codepleb

91

initializeМетод викликається після того, як всі @FXMLанотовані члени були введені. Припустимо, у вас є табличний вигляд, який ви хочете заповнити даними:

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

На додаток до вищезазначених відповідей, мабуть, слід зазначити, що існує застарілий спосіб реалізації ініціалізації. Існує інтерфейс, який називається Initializable з бібліотеки 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());
    }
}

Параметри:

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. 

І примітка до документів, чому працює простий спосіб використання @FXML public void initialize():

NOTEЦей інтерфейс замінено автоматичним введенням властивостей розташування та ресурсів у контролер. Тепер FXMLLoader автоматично викликає будь-який відповідний анотований метод no-arg initialize (), визначений контролером. Рекомендується застосовувати ін’єкційний підхід, коли це можливо.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.