当我正在学习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());
}
答案 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
上方等待一些时间,因为初始化场景需要一些时间。其他明智的场景将为空。