Несколько FXML с контроллерами, общий объект

Goodevening все,

Я нашел кучу сообщений уже по этой теме, но мне все еще не удается передать объект из 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 (образец.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;
}
}

Теперь я хочу захватить объект страны, когда 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? Я искал по этой проблеме часами и часами и читал каждый пост на StackOverflow об этом, но, похоже, я не нахожу недостающую ссылку... любая помощь (желательно с этим кодом) приветствуется!

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

2 ответов


FXML-это простая форма шаблон MVC. Файл FXML-это представление, контроллер очевиден, что упущено? Модель -- место, где вы храните все данные относительно текущего представления и, таким образом, которое вы можете использовать для обмена данными страны между контроллерами.


1. один из возможных подходов к внедрению модели "контекст". Рассмотрим случай, тогда у вас есть только одна модель для всего проекта, так что вы можете иметь глобальный контекст в форма Синглтон

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. Он будет работать лучше, если вы не хотите иметь глобальную модель приложения. Поэтому создайте аналогичный класс контекста, но без полей экземпляра, и:

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: