Контроллер Java FX 1 для нескольких FXML — используйте Singleton

В настоящее время я работаю над проектом Java FX и использую один контроллер для нескольких FXML (пожалуйста, не спрашивайте, почему)! Проблема, с которой я сталкиваюсь, заключается в том, что при каждом новом вызове FXML контроллер создает новый объект. Я хочу все время работать с одним и тем же контроллером и пытался реализовать конструктор контроллера как Singleton.

public Controller(){}
private static Controller controller = null;

public synchronized static Controller getInstance() {
    if (controller == null)
        controller = new Controller();
    return controller;
}

Эта стратегия дает мне следующую ошибку, так как кажется, что Java FX не может работать без создания нового конструктора для каждого FXML. Возможен ли другой подход?

Это ошибка, с которой я сталкиваюсь: /Users/dwome/git/4winner/4win/target/classes/win/javafxscene.fxml:11

at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
at javafx.fxml.FXMLLoader.access$700(FXMLLoader.java:103)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:934)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:971)
at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:220)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:744)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3214)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097)
at win.Main.start(Main.java:24)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$163(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$176(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$174(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$175(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)

Caused by: java.lang.IllegalAccessException: Class sun.reflect.misc.ReflectUtil can not access a member of class win.Controller with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.Class.newInstance(Class.java:436)
at sun.reflect.misc.ReflectUtil.newInstance(ReflectUtil.java:51)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:927)
... 19 more

Исключение запущенного приложения win.Main


person DWOME    schedule 21.10.2015    source источник


Ответы (2)


Я знаю, что вопрос старый, но, поскольку вы не прокомментировали, вы заставили его работать, и этот вопрос, кажется, много просматривается, я скажу, что я сделал, когда столкнулся с той же проблемой.

Я использовал то, что сказал Дарт Ниндзя в своем ответе.

Моя ошибка была не совсем такой, но я думаю, что это могло бы работать в любом случае, у меня был один контроллер для нескольких FXML.

Вот мои шаги:

  1. Удалено fx:controller="path.to.controller" из каждого FXML
  2. Я создал функцию loadFXML

    private void loadFXML(String pathToFile){
        try{
            InputStream fxmlStream = getInstance().getClass().getResourceAsStream(path);
            FXMLLoader loader = new FXMLLoader();
            loader.setBuilderFactory(new JavaFXBuilderFactory());
            loader.setLocation(getInstance().getClass().getResource(path));
            loader.setController(instance);
            BorderPane panee = (BorderPane) loader.load(fxmlStream);
            Scene scene = new Scene(pane);
        }
    }
    

Как видите, я делаю getInstance() и loader.setController(instance);

  1. Создать экземпляр instance... Я сделал это "храповым" способом

    private static Controller instance;
    static{
         if (instance == null)}
              instance = new Controller();
         }
    }
    

Может не помочь вашему делу, так как это было 6 месяцев назад, но может помочь другим!

person anthomaxcool    schedule 06.05.2016
comment
Очень ценю ваши усилия! - person DWOME; 09.05.2016

Используйте FXMLLoader для загрузки файла fxml. Вы можете вызвать внедрение контроллера через setController() .

В качестве альтернативы используйте Controller Factory при загрузке fxmls. Фабрика контроллеров может возвращать один и тот же объект контроллера

person Darth Ninja    schedule 22.10.2015
comment
У вас есть пример этого хорошего подхода? - person DWOME; 23.10.2015
comment
Этот пример может спасти жизнь! - person Kefirchiks; 27.03.2017