我如何在FX线程上放置东西?

问题描述 投票:2回答:2

我是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应用程序线程。 为什么,然后出现此错误,如何解决?

java exception-handling javafx runtime-error
2个回答
2
投票

JFXPanel初始化FX Application线程,因此它正在运行;但是您的代码未在该线程上执行。为了在FX Application Thread上执行代码,您可以调用Platform.runLater(...),它大致类似于Swing和AWT应用程序中的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));
}

2
投票

必须在FX Application线程中初始化或修改所有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);

希望这会有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.