2014-10-01 20 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); 

希望這會有所幫助。

相關問題