2014-05-01 4 views
0

В соответствии с документом this документ FXML можно рассматривать как часть «Просмотр» MVC. Объекты домена определены на стороне Java («Модель»). Я не могу узнать связь между «М» и «С». Я хочу изменить некоторые объекты домена (или инициировать модификацию) от контроллера: «М» < - «С»Объекты домена доступа от контроллера

Но код, подобный этому, не имеет отношения к Место, где я призываю FXMLLoader.load():

public class FXMLTableViewController { 
    @FXML private TableView<Person> tableView; 
    @FXML private TextField firstNameField; 
    @FXML private TextField lastNameField; 
    @FXML private TextField emailField; 

    @FXML 
    protected void addPerson(ActionEvent event) { 
     ObservableList<Person> data = tableView.getItems(); 
     data.add(new Person(firstNameField.getText(), 
      lastNameField.getText(), 
      emailField.getText() 
     )); 

     firstNameField.setText(""); 
     lastNameField.setText(""); 
     emailField.setText(""); 
    } 
} 

Этот код полностью отделен от остального кода приложения. Каков правильный способ установления такой связи?

ответ

2

Не используйте статический метод FXMLLoader.load(URL). Вместо этого создайте экземпляр FXMLLoader. Затем вы можете либо создать экземпляр контроллера самостоятельно, либо позвонить по телефону setController(...), либо вы можете установить фабрику контроллера.

Использование setController(...)

Так что у вас есть некоторый класс модели, назовем его Model. Определите контроллер взять ссылку на него:

public class MyController { 
    private final Model model ; 

    // usual @FXML-annotated fields, etc 

    public MyController(Model model) { 
     this.model = model ; 
    } 

    public void initialize() { ... } 

    // handler methods, etc... 
} 

Теперь удалить fx:controller атрибуты из файла FXML, и вместо того, чтобы сделать следующее:

final Model model = new Model(); 

FXMLLoader loader = new FXMLLoader(); 
loader.setLocation(getClass().getResource("path/to/fxml/file.fxml")); 
loader.setController(new MyController(model)); 
Parent root = loader.<Parent>load(); 

Использование setControllerFactory(...)

Если вам нужны или нужно использовать атрибуты fx:controller (например, если вы используете <fx:include ...> теги в своих FXML и вводящие вложенные контроллеры, которым также может потребоваться доступ к модели), вы можете вместо этого указать фабрику контроллера, которая фактически является функцией, которая сопоставляет типы контроллеров с экземплярами контроллера. FXMLLoader будет использовать это, чтобы определить, как создать объект из имени класса, указанного в атрибуте fx:controller.

Например:

final Model model = new Model(); 

FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml/file.fxml")); 
loader.setControllerFactory(new Callback<Class<?>, Object>() { 
    @Override 
    public Object call(Class<?> type) { 
     try { 
      for (Constructor<?> constructor : type.getConstructors()) { 
       if (constructor.getParameterCount()==1 && 
         constructor.getParameterTypes()[0]==Model.class) { 
        return constructor.newInstance(model); 
        } 
      } 
      // no matching constructor found, just call no-arg constructor as default: 
      return type.newInstance(); 
     } catch (Exception exc) { 
      exc.printStackTrace(); 
      return null ; // bail... 
     } 
    } 
}); 
Parent root = loader.<Parent>load(); 

Обратите внимание, что с этой версии:

  1. Любые FXML файлы включены будут использовать один и тот же контроллер завод, поэтому, если их контроллеры имеют конструктор, принимающий один параметр типа Model, они получат ссылку на тот же пример Model
  2. Если вы используете в своем приложении несколько FXMLLoader s, вы можете повторно использовать тот же самый контроль ller, чтобы передать тот же экземпляр Model загрузчикам, поэтому все контроллеры могут получить доступ к тому же экземпляру Model.

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

Контроллер завод является очень мощным и гибким механизмом. Например, было бы довольно легко определить фабрику контроллера, которая просто отложена до весны ApplicationContext. Таким образом, вы можете определить интерфейсы для контроллеров и просто указать имя интерфейса в файле FXML. Затем ваш конфигурационный файл Spring может определить, какую реализацию интерфейса контроллера использовать, и, конечно, может ввести модели (и объекты домена) в контроллер для вас.

Также см

Если вы делаете много этого, взгляните на Adam Bien's afterburner framework. Адам определяет фабрику повторного использования контроллера, которая загружает контроллеры и проверяет для них аннотированные поля @Inject и вводит экземпляр singleton в эти поля. Это дает большую гибкость, так как вы можете легко добавить к своим контроллерам больше общих ресурсов.

1

Вы можете создать экземпляр FXMLLoader и использовать метод нестатической нагрузки (или load()). После этого вы можете получить контроллер, используя метод getController().

Смежные вопросы