我想在用户登录应用程序时更改阶段。 我在Action中创建了一个线程,在其中我使用Platform.runLater来更新舞台并显示新的舞台。这是在被调用的方法中完成的。
所以我有以下代码:
的LoginController
private Stage primaryStage
@FXML
void btnLoginAction(ActionEvent event) throws ClassNotFoundException {
Runnable loginRunnable = new Runnable() {
public void run() {
....
if (user exists and password ok){
loadMainwindow();
}else{
show alert
}
};
Thread loginThread = new Thread(loginRunnable);
loginThread.start();
}
private void loadMainWindow() throws IOException {
dummyStage = (Stage) (btnLogin.getScene()).getWindow();
//I get the root borderpain from the Main class
BorderPane root = Main.getRoot();
//I load the anchorpanes i will use in the new stage
AnchorPane menuPane =
FXMLLoader.load(getClass().getResource("/views/Menu.fxml"));
AnchorPane centerPane =
FXMLLoader.load(getClass().getResource("/views/Home.fxml"));
//I set the anchorpanes to the root
root.setLeft(menuPane);
root.setCenter(centerPane);
Platform.runLater(new Runnable() {
public void run() {
primaryStage.show();
}
});
}
我遇到以下错误:
Exception in thread "Thread-3" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-3
at javafx.graphics/com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:291)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.graphics/javafx.scene.Parent$3.onProposedChange(Parent.java:493)
at javafx.base/com.sun.javafx.collections.VetoableListDecorator.add(VetoableListDecorator.java:206)
at javafx.graphics/javafx.scene.layout.BorderPane$BorderPositionProperty.invalidated(BorderPane.java:692)
at javafx.base/javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
at javafx.base/javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:147)
at javafx.graphics/javafx.scene.layout.BorderPane.setLeft(BorderPane.java:325)
at com.sener.dbgui.controller.LoginController.loadMainWindow(LoginController.java:90)
at com.sener.dbgui.controller.LoginController.access$4(LoginController.java:81)
at com.sener.dbgui.controller.LoginController$1.run(LoginController.java:63)
at java.base/java.lang.Thread.run(Thread.java:844)
第81行是“root.setLeft(menuPane)”行。
所以我猜问题是在修改根边框时必须运行JAVAFX线程。这是,我必须在Platform.runLater方法中包含“root.set ...”语句。
尽管如此,这意味着在控制器类中将root,menuPane和centerPane的多个变量设置为private,以便Platform.runLater进程可以访问它们,并且所有FXMLLoader,getwindow()和getRoot()方法都可以从Platform.runLater。
那么,将这个变量设置为private还是只调用Platform.runLater中的方法会更好吗?
选项1.在Platform.runLater内部调用方法
@FXML
void btnLoginAction(ActionEvent event) throws ClassNotFoundException {
Runnable loginRunnable = new Runnable() {
public void run() {
....
if (user exists and password ok){
Platform.runLater(new Runnable() {
public void run() {
loadMainwindow();
}
});
}else{
show alert
}
};
Thread loginThread = new Thread(loginRunnable);
loginThread.start();
}
如果从Platform.runLater解耦FXMLLoader,getWindow()和getRoot方法,该方法的代码将如下所示(我首先为AnchorPanes创建私有变量“menuPane”和“centerPane”,BorderPane“root”就像使用“primaryStage”变量):
选项2. CALL方法和DECOUPLE FMLXLOADERS,GETROOT()和GETWINDOW()方法来自Platform.runLater()
private AnchorPane menuPane, centerPane;
private Stage dummyStage;
private BorderPane root;
@FXML
void btnLoginAction(ActionEvent event) throws ClassNotFoundException {
Runnable loginRunnable = new Runnable() {
public void run() {
....
if (user exists and password ok){
loadMainwindow();
}else{
show alert
}
};
Thread loginThread = new Thread(loginRunnable);
loginThread.start();
}
private void loadMainWindow() throws IOException {
root = Main.getRoot();
primaryStage = (Stage) (btnLogin.getScene()).getWindow();
menuPane = FXMLLoader.load(getClass().getResource("/views/Menu.fxml"));
centerPane = XMLLoader.load(getClass().getResource("/views/Home.fxml"));
Platform.runLater(new Runnable() {
public void run() {
root.setLeft(menuPane);
root.setCenter(centerPane);
primaryStage.toFront();
primaryStage.show();
}
});
}
我想知道哪个选项是正确的。或许这些都是错误的,还有另一个解决方案。