Несколько FXML с контроллерами, общий объект
Добрый вечер всем,
Я уже нашел несколько сообщений на эту тему, но все еще не могу передать объект из Controller1 в Controller2. Есть ли где-нибудь полный учебник или пример проекта, который делает это?
Я зашел так далеко, пока не застрял:
Загородный класс
public class Country {
private SimpleStringProperty country = new SimpleStringProperty("");
//Constructor
public Country() {
}
//GETTERS
public String getCountry() {
return country.get();
}
//SETTERS
public void setCountry(String value) {
country.set(value);
}
@Override
public String toString() {
return getCountry();
}
}
Когда программа запускается, основной FXML загружается (Sample.fxml). Он содержит панель границ со строкой меню на верхней панели и панель контента в центре. При инициализации я создаю новый объект Country и сохраняю его в глобальной переменной. У меня есть метод, который загружает другой FXML в панель содержимого при нажатии элемента меню:
SampleController.java
public class SampleController implements Initializable {
@FXML
private Pane pContent;
private Country c;
@FXML
private void handleButtonAction(ActionEvent event) throws IOException {
System.out.println(c); //this prints Belgium, which is correct
URL url = getClass().getResource("Sub1.fxml");
FXMLLoader fxmlloader = new FXMLLoader();
fxmlloader.setLocation(url);
fxmlloader.setBuilderFactory(new JavaFXBuilderFactory());
pContent.getChildren().clear();
pContent.getChildren().add((Node) fxmlloader.load(url.openStream()));
}
@Override
public void initialize(URL url, ResourceBundle rb) {
c = new Country();
c.setCountry("Belgium");
}
public Country getCountryFromSampleController(){
return c;
}
}
Теперь я хочу захватить объект Country при загрузке Sub1.fxml, а это значит, что мне нужно получить объект country при initialize ():
Sub1Controller.java
public class Sub1Controller implements Initializable {
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
SampleController sp = new SampleController(); //I don't know how to fetch the original SampleController object
System.out.println(sp.getCountryFromSampleController());
//this prints null, which is ofcourse logical because I make a new SampleController object.
}
}
Вопрос, который у меня есть, как я могу получить "оригинальный" объект SampleController, чтобы я мог использовать метод getCountryFromRoot() для получения объекта Country со значением Belgium? Я искал эту проблему часами и прочитал все посты на Stackru об этом, но, похоже, я не нашел недостающую ссылку... любая помощь (желательно с этим кодом) приветствуется!
Извините за длинный пост, я старался быть максимально полным, иначе я никогда не пойму...
2 ответа
FXML - это простая форма шаблона MVC. Файл FXML является представлением, контроллер очевиден, что пропущено? Модель - это место, где вы храните все данные, относящиеся к вашему текущему представлению и, таким образом, которые вы можете использовать для обмена данными о стране между контроллерами.
1. Одним из возможных подходов к введению модели является "контекст". Давайте рассмотрим случай, тогда у вас есть только одна модель для всего проекта, чтобы вы могли иметь глобальный контекст в форме Singleton
public class Context {
private final static Context instance = new Context();
public static Context getInstance() {
return instance;
}
private Country country = new Country();
public Country currentCountry() {
return country;
}
}
Ваш SampleController будет иметь следующие изменения:
@Override
public void initialize(URL url, ResourceBundle rb) {
Context.getInstance().currentCountry().setCountry("Belgium");
}
А также SubController1
может получить к нему доступ таким же образом:
@Override
public void initialize(URL url, ResourceBundle rb) {
System.out.println(Context.getInstance().currentCountry().getCountry());
}
2. Другой способ - передать контекст SubController1
тогда вы загружаете это XML. Это будет работать лучше, если вы не хотите иметь глобальную модель приложения. Итак, создайте похожий класс Context, но без полей экземпляра, и:
public class Sub1Controller implements Initializable {
private Context context;
public void setContext(Context context) {
this.context = context;
// initialize country dependent data here rather then in initialize()
}
}
Установка контекста в SampleController
:
Context currentContext = new Context();
@Override
public void initialize(URL url, ResourceBundle rb) {
currentContext.currentCountry().setCountry("Belgium");
}
@FXML
private void handleButtonAction(ActionEvent event) throws IOException {
URL url = getClass().getResource("Sub1.fxml");
FXMLLoader fxmlloader = new FXMLLoader();
fxmlloader.setLocation(url);
fxmlloader.setBuilderFactory(new JavaFXBuilderFactory());
pContent.getChildren().clear();
pContent.getChildren().add((Node) fxmlloader.load(url.openStream()));
// here we go
((Sub1Controller)fxmlloader.getController()).setContext(currentContext);
}
С помощью API потока DataFX вы можете внедрить данные в экземпляры вашего контроллера с помощью CDI: