3

在学习 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 为空),所以我想知道,是否有一种方法在初始化后立即被触发?

当我将此代码附加到 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

4 回答 4

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();
    }
}
于 2012-07-16T23:15:06.173 回答
2

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

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() 方法中,只需从控制器获取数据作为通常的数据对象。

于 2012-07-30T08:27:59.497 回答
2

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

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

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

考虑到这一点,您可以制作另一个带有字段的静态对象,例如

private static Label lbl;

...

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

...

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

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

于 2012-07-16T19:26:09.583 回答
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();
    }

现在,当您要传递数据时,请从应用程序中的任何 Where / 任何类中调用上述方法,并使用一些数据:

      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,因为初始化场景需要一些时间。其他明智的场景将是空的。

于 2021-07-01T08:08:39.700 回答