混合Swing / FX:无法从fxml控制器处理对话框

时间:2013-11-10 12:50:20

标签: java swing javafx-2 fxml

场景:顶级容器是一个Swing JDialog,它有一些fx内容,包括触发处理按钮的fx按钮。在创建按钮并手动配置相应的eventHandler时,处理可以预期(对话框被隐藏)。通过fxml创建/配置按钮时,不会释放该对话框。下面的示例包含手动配置和fxml加载/绑定按钮,以查看不同的行为。

问题:

  • 这个例子有什么问题吗?
  • 预期的swing / fx交互是否存在差异(手动与fxml)?
  • 如何让它从fxml开始工作?

代码:

package fxml;

import java.io.IOException;

import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.FlowPane;

import javax.swing.JDialog;
import javax.swing.SwingUtilities;

public class DisposeExample {
    @FXML
    Button closeButton;

    Button fxButton;

    private JDialog dialog;

    /**
     * The action handler method used by fx buttons.
     */
    public void onAction(final ActionEvent ac) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                System.out.println("onAction: " +ac);
                dialog.dispose();
            }
        });
    }

    protected Button createFxButton() {
        Button fxButton = new Button("close from fx");
        fxButton.setOnAction(new javafx.event.EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                onAction(event);
            }
        });
        return fxButton;
    }

    public void initFX() {
        final JFXPanel fxPanel = new JFXPanel();
        dialog.add(fxPanel);

        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                FlowPane parent = null;
                try {
                    parent = FXMLLoader.load(DisposeExample.class.getResource(
                            "DisposeController.fxml"));
                } catch (IOException e) {
                    e.printStackTrace();
                }
                fxButton = createFxButton();
                parent.getChildren().add(fxButton);
                Scene scene = new Scene(parent);
                fxPanel.setScene(scene);
            }
        });
    }

    public DisposeExample() {
        dialog = new JDialog();
        dialog.setTitle("Simple Swing Dialog");
        initFX();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JDialog example = new DisposeExample().dialog;
                example.setSize(400, 400);
                example.setVisible(true);
            }
        });
    }
}

fxml内容:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<FlowPane id="Content" fx:id="windowPanel" 
    xmlns:fx="http://javafx.com/fxml" fx:controller="fxml.DisposeExample">
    <children>
        <Button fx:id="closeButton" onAction="#onAction" 
            prefHeight="35.0" prefWidth="300.0" text="Close (fxml controller)">
        </Button>
    </children>
</FlowPane>
顺便说一下:从今年年初开始有similar question,未得到答复。

修改

发生了一些奇怪的事情:在运行几分钟之后,它会抛出一个OutOfMemoryError - 更深层次的东西不会停止创建......什么?

java.lang.OutOfMemoryError: Java heap space
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2521)
at java.lang.Class.privateGetPublicMethods(Class.java:2641)
at java.lang.Class.privateGetPublicMethods(Class.java:2657)
at java.lang.Class.privateGetPublicMethods(Class.java:2657)
at java.lang.Class.privateGetPublicMethods(Class.java:2657)
at java.lang.Class.privateGetPublicMethods(Class.java:2657)
at java.lang.Class.privateGetPublicMethods(Class.java:2657)
at java.lang.Class.getMethods(Class.java:1457)
at sun.reflect.misc.MethodUtil.getMethods(MethodUtil.java:99)
at com.sun.javafx.fxml.BeanAdapter.updateMethodCache(BeanAdapter.java:265)
at com.sun.javafx.fxml.BeanAdapter.setBean(BeanAdapter.java:250)
at com.sun.javafx.fxml.BeanAdapter.<init>(BeanAdapter.java:213)
at javafx.fxml.FXMLLoader$Element.getValueAdapter(FXMLLoader.java:157)
at javafx.fxml.FXMLLoader$Element.getProperties(FXMLLoader.java:165)
at javafx.fxml.FXMLLoader$ValueElement.processValue(FXMLLoader.java:647)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:570)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2314)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2131)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2028)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2744)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2723)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2709)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2696)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2685)
at fxml.DisposeExample$3.run(DisposeExample.java:65)
at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:179)
at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:176)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:176)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)

修改

fyi:8u113中的行为相同,所以提交了issue in fx-jira,无法治愈的乐观主义者,我是:-)

3 个答案:

答案 0 :(得分:3)

  

这个例子有什么问题吗?

响亮的 - 引用Martin的(非常快速和明确的:-)评论该问题:

  

问题出在您的fxml文件中。

     

“fx:controller”属性获取类并创建一个新实例   它(使用默认的构造函数)。你的默认构造函数   DisposeExample类发布一个新的Runnable,它将加载相同的fxml   再次文件创建另一个DisposeExample类的实例。

     

您应该为控制器使用不同的类或设置   控制器手动使用setController()调用或使用   controller factory(setControllerFactory)。否则,没有办法   为FXMLLoader知道您想要使用您的特定   DisposeExample对象。

答案 1 :(得分:2)

错误警报 - 从FXML文件中删除控制器并将其设置在代码中。

FXMLLoader fxmlLoader = new FXMLLoader(DisposeExample.class.getResource("DisposeController.fxml"));
fxmlLoader.setController(DisposeExample.this);
parent = (FlowPane)fxmlLoader.load();

不幸的是,在这些寒冷的日子里,这也将破坏FX-CPU加热; - )

答案 2 :(得分:1)

那么你为什么不在swing线程上执行dispose?