在JavaFX2中,如何将ArrayList从一个场景传递到另一个场景?

在JavaFX2中,如何将ArrayList从一个场景传递到另一个场景?,java,arraylist,javafx,javafx-2,Java,Arraylist,Javafx,Javafx 2,因此,我已经尝试了几个小时来解决这个问题,之前在这些论坛上已经得到了回答,但我真的非常感谢一些帮助,因为没有人真正解决我的问题或提出非常不同的解决方案,我也不太确定该尝试什么(尽管我敢说,我已经尝试了所有这些) 问题是:我有一个JavaFX应用程序,它有6个场景和它们各自的控制器。我有一个Person类,它创建了一个对象,我想将该对象存储在全局的ArrayList中(也就是说,所有场景都可以访问),这样当我关闭应用程序时,我可以调用另一个方法将其保存到序列化文件中 在前两个场景中,我实际上没有使

因此,我已经尝试了几个小时来解决这个问题,之前在这些论坛上已经得到了回答,但我真的非常感谢一些帮助,因为没有人真正解决我的问题或提出非常不同的解决方案,我也不太确定该尝试什么(尽管我敢说,我已经尝试了所有这些)

问题是:我有一个JavaFX应用程序,它有6个场景和它们各自的控制器。我有一个Person类,它创建了一个对象,我想将该对象存储在全局的ArrayList中(也就是说,所有场景都可以访问),这样当我关闭应用程序时,我可以调用另一个方法将其保存到序列化文件中

在前两个场景中,我实际上没有使用ArrayList,因为它们是菜单,所以创建对象的实际方法直到第三个场景左右才运行

我已经成功地创建了场景,我可以在它们之间切换,我只是不知道

  • 在何处声明ArrayList(如果在main方法中,则为main类或Where?)
  • 如何在场景之间传递此ArrayList,以便所有场景都能够访问它们
  • 我当前使用此类在场景之间切换:

    public class SelectScene  {
        public void setScene(String fxmlFileName, String title, ActionEvent event) throws IOException{
            Stage stage = (Stage) ((Node)event.getSource()).getScene().getWindow();
            Parent root = FXMLLoader.load(getClass().getResource(fxmlFileName));
            Scene scene = new Scene(root);
            scene.getStylesheets().add(FinalDossier.class.getResource("style.css").toExternalForm());
            stage.setTitle(title);
            stage.setScene(scene);
        }
    

    非常感谢您的帮助:)

    我建议您查看我的系统架构。在我的示例中,您可以将arraylist存储在MyScreenController类中,因为所有屏幕都有对它的引用,有几种方法可以做到这一点:基本上,所有这些方法都不使用静态的
    FXMLLoader.load(URL)
    方法,而是创建一个
    FXMLLoader
    实例

    一种方法是在代码中创建控制器,用共享列表初始化它们,然后将它们传递给
    setController(…)
    。在此版本中,您将从FXML文件中删除
    fx:controller
    属性

    不过,在您的情况下,似乎更好的方法是为
    fxmloader
    定义一个控制器工厂。这是一个告诉
    fxmloader
    如何从
    fx:controller
    属性中定义的类名获取实例的对象。这只需要一点反射魔法。所以你会这样做

    public class SelectScene  {
    
    
        private Callback<Class<?>, Object> controllerFactory ;
    
        public SelectScene(final List<...> data) {
            controllerFactory = new Callback<Class<?>, Object>() {
                @Override
                public Object call(Class<?> type) {
                    try {
                        Constructor<?> constructor = type.getDeclaredConstructor(List.class);
                        return constructor.newInstance(data);
                    } catch (NoSuchMethodException exc) {
                        return type.newInstance();
                    } catch (Exception ex) {
                        // trouble...
                        ex.printStackTrace();
                        return null ;
                    }
                }
             };
        }
    
        public void setScene(String fxmlFileName, String title, ActionEvent event) throws IOException{
            Stage stage = (Stage) ((Node)event.getSource()).getScene().getWindow();
            FXMLLoader loader = new FXMLLoader(getClass().getResource(fxmlFileName));
            loader.setControllerFactory(controllerFactory);
            Parent root = (Parent)loader.load();
            Scene scene = new Scene(root);
            scene.getStylesheets().add(FinalDossier.class.getResource("style.css").toExternalForm());
            stage.setTitle(title);
            stage.setScene(scene);
        }
    }
    
    public类选择场景{
    私有回调,对象>(){
    @凌驾
    公共对象调用(类类型){
    试一试{
    构造函数=type.getDeclaredConstructor(List.class);
    返回构造函数.newInstance(数据);
    }捕获(NoSuchMethodException){
    返回类型:newInstance();
    }捕获(例外情况除外){
    //麻烦。。。
    例如printStackTrace();
    返回null;
    }
    }
    };
    }
    public void setScene(字符串fxmlFileName、字符串标题、ActionEvent事件)引发IOException{
    Stage Stage=(Stage)((节点)event.getSource()).getScene().getWindow();
    FXMLLoader=新的FXMLLoader(getClass().getResource(fxmlFileName));
    loader.setControllerFactory(controllerFactory);
    父根=(父)加载程序。加载();
    场景=新场景(根);
    scene.getStylesheets().add(FinalDossier.class.getResource(“style.css”).toExternalForm());
    舞台。片名(片名);
    舞台场景;
    }
    }
    
    对于需要访问共享数据的控制器,只需定义一个构造函数,其中的参数包含一个列表:

    public class MyController {
        private final List<...> data ;
        public MyController(List<...> data) {
            this.data = data ;
        }
        public void initialize() {
            // usual initialize method
        }
    }
    
    公共类MyController{
    私人最终名单数据;
    公共MyController(列表数据){
    这个数据=数据;
    }
    公共无效初始化(){
    //常用初始化方法
    }
    }
    
    对于没有该构造函数的控制器,控制器工厂将返回默认构造函数

    您可以在任何方便的地方定义该列表:直接在SelectScene类中(如代码所示),或者可以在前面定义它(例如,在start()方法中),并将其传递给SelectScene构造函数。这取决于你可能需要访问它的其他地方


    更新:完整示例

    谢谢,这似乎解决了问题。除此之外,现在我可以从任何类读取ArrayList,但我不能回写它(即更新它)。。。所以我可以在一个场景中添加内容,不同的场景可以看到这些变化。。。我该怎么做呢?只要将列表的同一个实例传递给每个控制器,就可以了。因此,要么确保只实例化一次SelectScene;或者实例化列表一次(比如在start方法中),并将相同的列表实例传递给SelectScene构造函数。如果需要动态观察更改,可能需要一个ObservableList而不是普通列表。为了能够使用SelectScene类中的方法(setScene),我在每个控制器中实例化它。。。因为我不能静态地做它,它会抛出一个错误。。。如何(或在何处)仅实例化一次,并且能够在所有场景中使用它?在这种情况下,您可以在SelectScene构造函数中将列表定义为参数,并使用该参数初始化字段。然后使用controllerFactory技术将单个列表实例传递给所有控制器,并将列表传递给SelectScene构造函数。这样,您就有了多个SelectScenes,但它们都共享同一个列表。我会更新一下代码。。。关键的是,您只创建一个列表。如果您在主应用程序的start(…)方法中创建列表,而不是在其他任何地方,则可以保证这一点