Как инициализировать контроллеры JavaFX с тем же объектом модели?

сценарий

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

к чему я привык

в Swing, если я хочу, чтобы все представления ссылались на одну и ту же модель, я бы передал модель в конструктор.

что я сейчас делаю

в JavaFX я передаю модель, имея метод setter в представлениях / контроллерах (menubars, split стекла, вкладки,...), после загрузки каждого вида / контроллера. Я нахожу это очень вульгарным и громоздким. Кроме того, я считаю, что это не сработает, потому что в некоторых ситуациях мне нужно, чтобы модель уже существовала в контроллере до инициализации некоторых виджетов контроллера.

Непримечательные Альтернативы

(Примечание: я ссылаюсь на эти вопросы stackoverflow:

  • JavaFX 2.0 практическое применение.getParameters () в a Контроллер.файл java
  • передача параметров JavaFX FXML
  • несколько FXML с контроллерами, share object
  • передача параметров контроллеру при загрузке FXML)

  • Инъекции Зависимостей

    • я просмотрел этот сайт,http://www.zenjava.com/2011/10/23/javafx-2-0-fxml-and-spring/, и я посмотрел немного в Google Guice, но я не вижу способа упрощенно дать каждому JavaFX view/controller тот же объект модели. Казалось, что инъекция будет вводить другую модель для каждого вида / контроллера.
  • сохранение объекта модели как общедоступной статической переменной

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

    • Я хочу, чтобы каждый контроллер загружался в свой конструктор, и я хочу, чтобы каждый пользовательский контроллер автоматически вводился в его Родительский контроллер. Например, вкладка Обзор карты загружается следующим образом:

      public CardOverviewTab() {
          FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("card_overview_tab.fxml"));
          fxmlLoader.setRoot(content);
          fxmlLoader.setController(this);
      
          try {
              fxmlLoader.load();
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
      
    • и контроллер SingleGameSetup вкладка Обзор карты автоматически вводится в переменную:

      public class SingleGameSetupController extends AnchorPane {
      
          @FXML private CardOverviewTab cardOverviewTab;
      
          // Rest of the class
      }
      
    • и часть fxml, содержащая вкладку Обзор карты выглядит следующим образом:

      <CardOverviewTab fx:id="cardOverviewTab" />
      
    • таким образом, мне не нужно беспокоиться о РУЧНОЙ загрузке контроллера, но у меня все еще есть проблема установки модели.

  • установка контроллера на FXMLLoader

    • эта опция аналогична к чему я привык, передавая модель в качестве параметра в конструктор, но у нее все еще есть проблема загрузки контроллеров вручную с помощью FXMLLoader.
  • Автобусная Событие

    • я не слишком много читал об этом, но из того, что я прочитал, шина событий кажется неактивной и устаревшей.
  • Синглтон

    • это похоже на наличие общедоступной статической ссылки к объекту модели, который могут получить контроллеры, но снова я ищу лучшее решение. Кроме того, я не хочу модель singleton.

то, что я ищу

есть ли способ передать объект модели вокруг менее громоздким способом? Я ищу способ, который так же прост, как передача модели конструктору, но я не хочу иметь дело с ручной загрузкой контроллеров через FXMLLoader или установкой модели после контроллеры загружены. Возможно, наличие класса для извлечения модели-лучший вариант, но я спрашиваю на всякий случай, есть ли лучший способ.

3 ответов


обновление

кроме Форсажа.fx, также проверка Глюонной Воспламенить:

Gluon Ignite позволяет разработчикам использовать популярные фреймворки инъекций зависимостей в своих приложениях JavaFX, в том числе внутри своих контроллеров FXML. Gluon Ignite создает общую абстракцию над несколькими популярными фреймворками инъекций зависимостей (в настоящее время Guice, Spring и Dagger, но мы планируем добавить больше, когда спрос станет очевидным). С полная поддержка JSR-330 Gluon Ignite делает использование инъекции зависимостей в приложениях JavaFX тривиальным.

впрыска модельных объектов в регуляторы также через @впрыскивает,подобный форсажной камере.fx.

Предлагаемый Подход

поскольку вы, похоже, ищете структуру инъекции зависимостей, я думаю, что ваш лучший вариант-использовать форсаже.база Форекс.

форсаже.fx обеспечивает способ инъекции модели объекты в контроллеры JavaFX с помощью стандартного Java @Inject Примечание.

Альтернативные Системы Впрыска Зависимостей

Spring большой и сложный и, если вам не нужно много других функций для вашего приложения, не следует рассматривать из-за его сложности.

Guice намного проще, чем Spring и разумный выбор, если вам нужна структура инъекции зависимостей с многочисленными функциями, такими как класс поставщика. Но, судя по звуку, вам не нужны все функции, которые предоставляет Guice, поскольку вы просто хотите, чтобы способ передачи одноэлементных экземпляров объектов в вашем приложении без явного их поиска.

Итак, попробуйте Форсаж.fx и посмотреть, соответствует ли он вашим потребностям.

форсаже.пример кода fx

вот пример инъекции экземпляра модели (NotesStore) в контроллер с использованием форсажа.fx. Образец непосредственно скопировано из форсаже.Форекс документация.

import com.airhacks.afterburner.views.FXMLView;

public class NoteListView extends FXMLView {
    //usually nothing to do, FXML and CSS are automatically
    //loaded and instantiated
}

public class AirpadPresenter implements Initializable {    
    @Inject // injected by afterburner, zero configuration required
    NotesStore store;

    @FXML // injected by FXML
    AnchorPane noteList;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        //view constructed from FXML
        NoteListView noteListView = new NoteListView();

        //fetching and integrating the view from FXML
        Parent view = noteListView.getView();
        this.noteList.getChildren().add(view);
    }
}

followme.fx базовый пример приложения, демонстрирующий, как использовать Форсаж.fx. У меня было несколько проблем с получением followme.fx работает прямо из коробки из-за несовместимости зависимостей Maven, поэтому я раздвоенный код и исправлены некоторые проблемы, которые помешали мне использовать его из коробки.

ответы на дополнительные вопросы от комментарии

Итак, из примера NoteStore вы говорите, что все, что мне нужно сделать, это добавить зависимость структуры afterburner и поместить @Inject в мою переменную модели?

нет, вам также нужно создать связанный класс, который расширяет FXMLView и создает экземпляр этого с новым вызовом (подобно тому, как NotesListView создается в примере кода выше). Если вы заинтересованы в продолжении исследования Форсажа.основы Форекс, а затем использовать мной.проект fx в качестве основы, потому что он предоставляет полный исходный код для очень простого исполняемого образца с использованием фреймворка.

я попробовал Google guice и заставил его работать . . . вы увидите в конструкторе, что объект настроек игры вводится вручную.

Я не думаю, что вам нужно использовать инжектор Guice вручную, как это. Я думаю, вы можете установить контроллер factory на экземпляре FXMLLoader для запуска инъекции. Вот как FXMLView в Форсаже.Форекс-это. Точная деталь механизма впрыска, используемого в Guice, будет отличаться от форсажной камеры.механизм fx, но я думаю, что широкая концепция установки фабрики контроллера остается аналогичной.

существует демонстрация фабрики контроллера набора с использованием FXML и Guice в ответе на:связывание FXML и контроллера в конфигурации модуля Guice.

жаль, что нет больше простой способ сделать это, который не вызывает у вас столько трудностей.

как несущественная личная заметка, я как бы амбивалентен по теме фреймворков инъекций зависимостей в целом. Конечно, они могут помочь, но много раз для простых вещей я часто в порядке с синглтоном с методом getInstance, а не с более сложной структурой. Тем не менее, я вижу, как в больших проектах они могут быть полезны, и, конечно, они очень популярны в некоторых Java интегрированные системы.


Я исследовал эту проблему, и я обнаружил, что инъекция зависимостей вместе с синглтоном (для модели) является моим оптимальным дизайном. Я узнал, что наличие метода setter для модели в каждом из моих контроллеров является формой инъекции зависимостей, как и передача модели через конструктор. Spring и Guice рамки, чтобы помочь этому.

Я попытался использовать Spring, как указано здесь:http://www.zenjava.com/2011/10/23/better-controller-injection/ но я столкнулся с проблемой, когда класс конфигурации попытался загрузить контроллер, он не смог загрузить контроллеры-члены. Возможно, это был не весенний выпуск, но я решил, что мне не нужно тратить время, чтобы заставить его работать. Кроме того, мне пришлось бы просмотреть все мои файлы контроллера и отредактировать способ их создания.

обыскав и сделав много чтения, я обнаружил, что эта статья лучше всего выражает то, что я хотел бы сделать: https://forums.oracle.com/thread/2301217?tstart=0. Поскольку статья ссылается на предлагаемые улучшения, эти улучшения еще не существуют в JavaFX. Но когда они это сделают, я буду их реализации. Просто для примера, будучи в состоянии ввести модель через fxml:

<usevar name="model" type="com.mycom.myapp.ModelObject"/>

платформа DataFX имеет новый API, называемый DataFX-Flow. С помощью этого API вы можете просто вводить объекты в контроллере представления. Другое, что Форсаж.здесь поддерживаются области fx. Вы можете найти пример здесь:http://www.guigarage.com/2013/12/datafx-controller-framework-preview/