将对象从一个场景传递到另一个场景

时间:2012-07-16 16:06:54

标签: javafx-2 scene fxml

当我正在学习JavaFX2的新世界时,我偶然发现了另一个恼人的问题。我正在开发一个包含多个场景(~10个场景)的程序。为此,我创建了一个这样的小类:

public class SceneSelector {
    ...
    public void setScene(Stage stage, String fxmlfilename, ObservableList ol) throws Exception{
        String s = "../" + fxmlfilename;
        Parent root = FXMLLoader.load(getClass().getResource(s));
        root.setUserData(ol);

        Scene scene = new Scene(root);
        stage.setScene(scene);

        //show the stage
        stage.show();
    }
}

这个类适用于在场景之间切换。 现在的问题是我有时需要将数据从Scene1传递到Scene2。我试图通过为新场景设置setUserData()来做到这一点,这个场景基本上只适用于一件事。新场景初始化时如何获取用户数据? (因为那时节点仍为空)

场景1的代码:

//Code connected to a button that opens the new Scene
private void openLabID(ActionEvent event) throws Exception {       
    final Stage primaryStage = (Stage) btnNewScene.getScene().getWindow();

    ObservableList<Koe> olAfTeWerkenKoeien = DA_Koe.getAfTeWerkenKoeien();
    ss.setScene(primaryStage, "GUI/scenes/koe/Koe.fxml", olAfTeWerkenKoeien);
}

场景2的代码:

public void initialize(URL url, ResourceBundle rb) {
    Scene s = lbl.getScene();
    ObservableList<Koe> olAfTeWerkenKoeien = (ObservableList<Koe>) s.getRoot().getUserData();
    System.out.println(olAfTeWerkenKoeien.size());
} 

当然,Scene s在此时给出一个空值(因为此时lbl为null),所以我想知道,是否有一个方法在初始化后立即被触发?

当我将此代码附加到Scene2上的按钮时,它就像魅力一样,但它应该自动加载。

编辑: 使用setMyData()方法设置数据不是问题,但检索它是:

public ObservableList<Koe> getMyData() {
   return this.myData;
}

如何在控制器初始化时获取CustomScene对象?因为这样做会导致NullPointerException(因为btnSluiten尚未初始化):

@Override
public void initialize(URL url, ResourceBundle rb) {
    ...
    Stage stage = (Stage) btnSluiten.getScene().getWindow();
    CustomScene cs = (CustomScene) stage.getScene();

    ObservableList<Koe> olKoe = cs.getMyData();

    System.out.println(olKoe.size());
}

4 个答案:

答案 0 :(得分:2)

我相信你错过了Scene对象中的那个点。从Scene类文档中我们可以看到:

  

JavaFX Scene类是场景图中所有内容的容器。

这意味着Scene对象只是一个容器,因此它不应该包含任何数据。

考虑到这一点,您可以使用

等字段创建另一个静态对象
private static Label lbl;

...

public static Label getLbl()
{
    return MyStaticObject.Lbl;
}

...

并使用它来存储您的lbl(或任何适合您的信息的对象),然后静态检索它。

我这样做是为了从我的应用程序中设置其他Stage对象的所有者。我希望它有所帮助。干杯

答案 1 :(得分:2)

如果您真的希望您的场景有意义(也就是存储特定的用户数据),您可以扩展它:

public class FooScene extends Scene {
   private ObservableList myData;

   public setMyData(ObservableList data) {
       this.myData = data;
       //handle data
   }
}

在场景初始化之后调用设置代码的最简单方法是自己调用它:

public class SceneSelector {
    ...
    public void setScene(Stage stage, String fxmlfilename, ObservableList ol) throws Exception{
        String s = "../" + fxmlfilename;
        Parent root = FXMLLoader.load(getClass().getResource(s));

        // first: add root to scene
        FooScene scene = new FooScene(root);
        // second: apply data to scene (or root)
        scene.setMyData(ol);
        stage.setScene(scene);

        //show the stage
        stage.show();
    }
}

答案 2 :(得分:1)

您可以将控制器用于场景并通过控制器传递数据:

String filePath1 =  "../" + fxmlfilename;
URL location1 = YourController1.class.getResource(filePath1);
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(location1);
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
Parent root = (Node) fxmlLoader.load(location1.openStream());

YourController1 ctrl1 = (YourController1) fxmlLoader.getController();

然后您可以将数据分配给控制器:

ctrl1.setUserData();

最后,只需显示场景:

Scene scene = new Scene(root);
stage.setScene(scene);

//show the stage
stage.show();

在控制器的initialize()方法中,只需从控制器获取数据作为通常的数据对象。

答案 3 :(得分:0)

@Sergey Grinev 的一些补充:

创建自定义场景:

package sample;

import javafx.scene.Parent;
import javafx.scene.Scene;

public class DataPassingScene extends Scene {

    public DataPassingScene(Parent parent) {
        super(parent);
    }

    String tafsir;

    public String getTafsir() {
        return tafsir;
    }

    public void setTafsir(String tafsir) {
        this.tafsir = tafsir;
    }
}

假设你的 Main Class Name 是 App.java,然后创建一个方法来显示新的 Stage :

public  static void showLayout (Stage primaryStage, String fxmlFileName, String stringData) throws IOException {

        Parent root = FXMLLoader.load(Objects.requireNonNull(App.class.getClassLoader().getResource(fxmlFileName)));
        DataPassingScene scene =  new DataPassingScene(root);

        scene.setTafsir(stringData); // Here we pass the data 

        primaryStage.setScene(scene);
        primaryStage.show();
    }

现在当你想传递数据时,从你的应用程序中的任何地方/任何类调用上面的方法,并使用一些数据:

      String tafsir = "This My Data" ; 

      try {
      App.showLayout(new Stage(), "showTafsirFxml.fxml",tafsir);
     } catch (IOException e) {
       e.printStackTrace();
    }

然后在您的控制器中获取数据。要获得场景,您必须获得舞台,并且要获得您使用的 FXML 元素之一的舞台,假设这里您的元素是一个按钮,称为 closeButton,所以:

@FXML
    private Button closeButton;

@Override
    public void initialize(URL url, ResourceBundle rb) {

        Platform.runLater(new Runnable() {
            @Override public void run() {

                Stage stage = (Stage) closeButton.getScene().getWindow();
                DataPassingScene  scene = (DataPassingScene) stage.getScene();
                String s = scene.getTafsir(); // Here we get the Data
                if(s!=null)
                    System.out.println("This is Tafsir From Highlight Table: "+s);
                else         
                System.out.println("Data Passing Null");
            }});
 
    }

因为,您必须在 runLater 上方等待一些时间,因为初始化场景需要一些时间。其他明智的场景将为空。