Swing嵌入JavaFX后EmbeddedWindow转Stage失败,求FXML窗口关闭方案
问题根源
你遇到的ClassCastException是因为嵌入在JFXPanel中的JavaFX场景,其所属窗口并非独立的javafx.stage.Stage,而是com.sun.javafx.stage.EmbeddedWindow——这是JavaFX为Swing嵌入场景专门生成的内部窗口类型,强行转Stage自然会报错。
解决方案
根据你的需求,提供两种直接可行的处理方式:
方式一:直接操作上层Swing窗口(推荐)
因为JavaFX界面是依附于Swing窗口(JFrame/JDialog)存在的,关闭对应的Swing窗口就能达到关闭当前嵌入界面的效果,同时可以启动下一个界面。
步骤:
- 在FXML控制器中添加Swing窗口的引用:
public class YourFXMLController { private JFrame parentSwingFrame; // 提供设置父窗口的方法 public void setParentSwingFrame(JFrame parentFrame) { this.parentSwingFrame = parentFrame; } // 关闭按钮的事件处理方法 @FXML private void onCloseButtonClicked(ActionEvent event) { // 关闭当前Swing窗口 parentSwingFrame.dispose(); // 在这里启动下一个界面(可以是新的Swing窗口,或者新的JFXPanel嵌入界面) launchNextInterface(); } private void launchNextInterface() { // 示例:打开新的Swing窗口 JFrame nextFrame = new JFrame("下一个界面"); nextFrame.setSize(800, 600); nextFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); nextFrame.setVisible(true); } }
- 在初始化JFXPanel的Swing代码中,传递窗口引用给控制器:
public class SwingMain { public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JFrame mainFrame = new JFrame("嵌入JavaFX的界面"); JFXPanel fxPanel = new JFXPanel(); mainFrame.add(fxPanel); // 加载FXML并获取控制器 try { FXMLLoader loader = new FXMLLoader(SwingMain.class.getResource("your.fxml")); Parent root = loader.load(); YourFXMLController controller = loader.getController(); // 传递Swing窗口引用 controller.setParentSwingFrame(mainFrame); fxPanel.setScene(new Scene(root)); mainFrame.setSize(800, 600); mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainFrame.setVisible(true); } catch (IOException e) { e.printStackTrace(); } }); } }
方式二:替换JFXPanel中的场景(无需关闭窗口)
如果不需要关闭整个Swing窗口,只是切换FXML内容,可以直接替换JFXPanel的Scene,避免窗口关闭再打开的开销:
@FXML private void switchToNextScene(ActionEvent event) { // 从事件源获取当前场景,再拿到EmbeddedWindow,最后获取对应的JFXPanel Node sourceNode = (Node) event.getSource(); Scene currentScene = sourceNode.getScene(); EmbeddedWindow embeddedWindow = (EmbeddedWindow) currentScene.getWindow(); JFXPanel fxPanel = (JFXPanel) embeddedWindow.getHost(); // 加载下一个FXML并替换场景 try { Parent nextRoot = FXMLLoader.load(getClass().getResource("next.fxml")); fxPanel.setScene(new Scene(nextRoot)); } catch (IOException e) { e.printStackTrace(); } }
内容的提问来源于stack exchange,提问作者Minh Long Vu
相关产品推荐
相关产品推荐

