我是JavaFX的新手(尝试从Swing迁移),并且我试图先创建一个非常基本的窗口。但是,我一直得到以下运行时异常:
Exception in thread "main" java.lang.IllegalStateException: Not on FX application thread; currentThread = main
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:210)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:393)
at javafx.scene.Scene.<init>(Scene.java:374)
at javafx.scene.Scene.<init>(Scene.java:232)
at bht.tools.util.upd.TestDialog.initGUI(TestDialog.java:39)
at bht.tools.util.upd.TestDialog.<init>(TestDialog.java:24)
at bht.tools.util.upd.TestDialog.main(TestDialog.java:52)
package bht.tools.util.upd;
import java.awt.Window;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javax.swing.JDialog;
/**
* TestDialog is copyright Blue Husky Programming ©2014 GPLv3 <hr/>
*
* @author Kyli of Blue Husky Programming
* @version 1.0.0
* - 2014-09-30 (1.0.0) - Kyli created TestDialog
* @since 2014-09-30
*/
public class TestDialog extends JDialog
{
public TestDialog(Window owner)
{
super(owner);
initGUI();
}
private JFXPanel holder;
private Scene interior;
private ProgressBar progressBar;
private GridPane root;
private void initGUI()
{
{
holder = new JFXPanel();
setContentPane(holder);
root = new GridPane();
interior = holder.getScene();
if (interior == null)
holder.setScene(interior = new Scene(root));
interior.setRoot(root);
}
{
progressBar = new ProgressBar();
progressBar.setProgress(-1);
root.add(progressBar, 0, 1);
}
pack();
}
public static void main(String[] args)
{
new TestDialog(null).setVisible(true);
}
}
但是,查看JFXPanel
源代码,构造函数调用其initFX()
方法,该方法初始化FX应用程序线程。 为什么我会收到此错误,我该如何解决?
答案 0 :(得分:2)
JFXPanel
初始化FX应用程序线程,因此它现在正在运行;但是你的代码没有在该线程上执行。为了在FX应用程序线程上执行代码,您可以在Swing和AWT应用程序中调用Platform.runLater(...)
,它大致类似于SwingUtilities.invokeLater(...)
。
这或多或少直接来自tutorial,但对于您的示例代码,您可以这样做
package bht.tools.util.upd;
import java.awt.Window;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javax.swing.JDialog;
/**
* TestDialog is copyright Blue Husky Programming ©2014 GPLv3 <hr/>
*
* @author Kyli of Blue Husky Programming
* @version 1.0.0
* - 2014-09-30 (1.0.0) - Kyli created TestDialog
* @since 2014-09-30
*/
public class TestDialog extends JDialog
{
public TestDialog(Window owner)
{
super(owner);
initGUI();
}
private JFXPanel holder;
private Scene interior;
private ProgressBar progressBar;
private GridPane root;
private void initGUI()
{
holder = new JFXPanel();
setContentPane(holder);
Platform.runLater( () -> initJFXPanel(holder) );
pack();
}
private void initJFXPanel(JFXPanel holder) {
root = new GridPane();
interior = holder.getScene();
if (interior == null)
holder.setScene(interior = new Scene(root));
interior.setRoot(root);
progressBar = new ProgressBar();
progressBar.setProgress(-1);
root.add(progressBar, 0, 1);
}
public static void main(String[] args)
{
new TestDialog(null).setVisible(true);
}
}
请注意,你也打破了Swing的线程规则,尽管我认为(自从我使用Swing编程以来已经有一段时间了)Swing已经过防弹以确保代码能够正常工作。但你的主要方法应该是
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> new TestDialog(null).setVisible(true));
}
答案 1 :(得分:2)
必须在FX应用程序线程中初始化或修改所有JavaFX控件,即调用Platform.runLater(() -> {
//your JavaFX code
});
JFXPanel可以在SwingUtility线程内初始化,但是必须在FX Application线程中设置JFXPanel上的JavaFX场景。例如:
//still on Swing thread
JFXPanel panel = new JFXPanel();
//now setting the scene to be embedded on the JFXPanel
//this must be done inside the FX Application thread
Platform.runLater(() -> {
Group group = new Group();
group.getChildren.addAll(new Button("Cancel"), new Button("Save"), new Text("Status"));
panel.setScene(new StackPane(group))});
//back on the Swing thread
frame.add(panel);
希望这有帮助。