JavaFX. Метод инициализации контроллера и пружину @PostConstruct нельзя использовать вместе - PullRequest
0 голосов
/ 18 апреля 2020

Ниже мой контроллер для моего проекта javafx. Моя цель состоит в том, чтобы получить некоторые значения по умолчанию, настроенные в классе DemoConfig, который внедряется как компонент в DemoController, поэтому я должен использовать @ PostConstuct.

И только для того, чтобы значение могло быть правильно инициализировано, контроллер должен реализовать метод initialize.

Вот код DemoController:

@Component
public class DemoController implements Initializable
{

    public TextField platformName;

    public TextField platformVersion;

    public TextField deviceName;

    public TextField appActivity;

    public TextField appPackage;

    @Autowired
    private DemoConfig demoConfig;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle)
    {
        platformName.setText(demoConfig.getPlatformName());

        platformVersion.setText(demoConfig.getPlatformVersion());

        deviceName.setText(demoConfig.getDeviceName());

        appActivity.setText(demoConfig.getAppActivity());

        appPackage.setText(demoConfig.getAppPackage());
    }

    @PostConstruct
    public void init() {
        platformName = new TextField(demoConfig.getPlatformName());

        platformVersion = new TextField(demoConfig.getPlatformVersion());

        deviceName = new TextField(demoConfig.getDeviceName());

        appActivity = new TextField(demoConfig.getAppActivity());

        appPackage = new TextField(demoConfig.getAppPackage());
    }


}

На самом деле init () и initialize (URL, ResourceBundle) делают то же самое, но я не могу применить @PostConstruct инициализировать (URL, ResourceBundle), поскольку приведенное ниже исключение:

Причина: java .lang.IllegalStateException: аннотации метода жизненного цикла требуется метод без аргументов:

Я могу согласиться с тем, что эти два метода работают вместе, но на самом деле метод init () только для того, чтобы гарантировать, что bean-компонент demoConfig будет правильно введен перед инициализацией. Интересно, есть ли более элегантный способ сделать это кодирование? Спасибо!

1 Ответ

2 голосов
/ 20 апреля 2020

Ваш метод init() полностью избыточен и должен быть удален. Правильный класс контроллера должен выглядеть следующим образом:

@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class DemoController implements Initializable
{
    @FXML
    private TextField platformName;

    @FXML
    private TextField platformVersion;

    @FXML
    private TextField deviceName;

    @FXML
    private TextField appActivity;

    @FXML
    private TextField appPackage;

    @Autowired
    private DemoConfig demoConfig;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle)
    {
        platformName.setText(demoConfig.getPlatformName());

        platformVersion.setText(demoConfig.getPlatformVersion());

        deviceName.setText(demoConfig.getDeviceName());

        appActivity.setText(demoConfig.getAppActivity());

        appPackage.setText(demoConfig.getAppPackage());
    }

}

Причина этого объясняется @ slaw в комментарии к вопросу. Для полноты я повторю эту информацию здесь:

При условии, что все настроено правильно в коде, который вы не опубликовали , когда вы вызываете load() на вашем FXMLLoader, произойдет следующее:

  1. FXMLLoader прочитает файл F XML и, увидев атрибут fx:controller, получит экземпляр указанного класса, используя его фабрику контроллеров. Поскольку вы предположительно сконфигурировали фабрику контроллера для использования контекста приложения Spring для предоставления контроллера, он будет запрашивать компонент DemoController из контекста приложения.
  2. Контекст приложения Spring будет создавать экземпляр DemoController.
  3. Контекст приложения Spring вводит любые зависимости в экземпляр DemoController. В этом случае это означает, что будет введено поле demoConfig.
  4. Контекст приложения Spring будет вызывать любые @PostConstruct -аннотированные методы. В исходной версии это означает, что он вызовет метод init(), который создает экземпляры текстовых полей и устанавливает для их текста значения из demoConfig. Поскольку эти текстовые поля не определены в файле F XML, они не являются частью пользовательского интерфейса , и это не имеет видимого эффекта. В правильной версии выше нет методов, помеченных @PostConstruct, и этот шаг ничего не делает.
  5. FXMLLoader продолжает анализ файла F XML, создавая экземпляры текстовых полей, определенных в нем. Если их fx:id атрибуты соответствуют именам либо public полей, либо (лучше) @FXML -аннотированных неопубликованных c полей, эти поля будут инициализированы текстовыми полями, определенными как часть синтаксического анализа F XML файл. (Это текстовые поля, которые являются частью пользовательского интерфейса.) Таким образом, в исходной версии текстовые поля, инициализированные в методе init(), немедленно заменяются текстовыми полями, определенными в файле F XML (поэтому вся работа, выполненная в методе init(), немедленно теряется).
  6. Метод initialize() вызывается на контроллере. Определение этого метода как в вашей версии, так и в версии, которую я выложил выше, теперь устанавливает текст правильных текстовых полей (т. Е. Тех, которые определены в файле F XML и являются частью пользовательского интерфейса). до значений в demoConfig.

Как видите, все, что вы делаете в своем методе init(), является избыточным (поскольку задает текст текстовых полей, которые никогда не отображаются в пользовательском интерфейсе), и в любом случае немедленно отменяется (поскольку FXMLLoader немедленно заменяет текстовые поля, которые он определяет, новыми текстовыми полями.)

Следовательно, вы должны просто удалить метод init(), как показано выше. Если это не дает желаемого результата, в коде, который вы не опубликовали, есть другие ошибки.

Обратите внимание, что я также изменил область действия контроллера на prototype. Если бы вы загружали файл F XML более одного раза, вы каждый раз получали бы новый набор текстовых полей, и вам понадобился бы новый экземпляр контроллера специально для этого набора элементов управления. При использовании Spring с JavaFX все контроллеры всегда должны быть прототипами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...