2014-10-01 19 views
2

我是JavaFX的新手(尝试从Swing中移出),并试图首先创建一个非常基本的窗口。不过,我不断收到以下运行时异常:如何在FX线程上放置东西?

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

所以你试图将一个FX组件嵌入到一个Swing对话框中?我不认为这是可能的。 AFAIK只有相反的机制。 查看新的Application类的基本开始。 – Ray 2014-10-01 16:17:46

+2

当然有可能;和[详细记录](http://docs.oracle.com/javase/8/javafx/interoperability-tutorial/swing-fx-interoperability.htm#CHDIEEJE)。 – 2014-10-01 16:20:09

+1

只是一个评论:如果你试图做一些简单的事情,只是为了让自己的脚湿润,将Swing和FX组合起来可能不是一个很容易开始的地方,因为你必须使用两个不同的UI线程。为什么不从一个简单的全功能应用程序开始? – 2014-10-01 16:31:15

回答

2

JFXPanel初始化FX应用程序线程,所以它现在正在运行;但是你的代码没有在该线程上执行。为了在FX应用程序线程上执行代码,您可以拨打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

所有JavaFX控件必须进行初始化或FX应用程序线程内被修改,那就是通过调用Platform.runLater(() -> { //your JavaFX code });

JFXPanel可以初始化SwingUtility线程内,但设置一个JavaFX JFXPanel上的场景必须在FX Application线程中完成。例如:

//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); 

希望这会有所帮助。

相关问题