带控制器的多个FXML,共享对象

时间:2012-08-28 20:08:17

标签: controller javafx-2 fxml javafx-8

为每个人服务,

我已经在这个主题上找到了很多帖子,但我仍然无法将一个对象从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;
}
}

现在我希望在加载Sub1.fxml时捕获Country对象,这意味着我需要在initialize()上获取country对象:

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()方法获取值为Belgium的Country对象?我一直在搜索这个问题好几个小时,并且已经阅读了关于这个的StackOverflow上的每一篇文章,但似乎我没有找到缺失的链接...任何帮助(最好使用此代码)表示赞赏!

对于长篇文章感到抱歉,我尽量做到尽可能完整但我永远不会理解...

2 个答案:

答案 0 :(得分:47)

FXML是MVC pattern的一种简单形式。 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);
}

答案 1 :(得分:3)