3

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

问题:

  • 这个例子有什么问题吗?
  • 预期的摆动/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>

BTW:今年年初有一个类似的问题,没有答案。

编辑

发生了一些奇怪的事情:运行了几分钟后,它抛出了 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)

编辑

仅供参考:8u113 中的行为相同,因此在 fx-jira 中提出了问题,我是无可救药的乐观主义者 :-)

4

3 回答 3

3

这个例子有什么问题吗?

一个响亮的“是” - 引用马丁(非常快速和清晰:-)对该问题的评论:

问题出在您的 fxml 文件中。

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

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

于 2013-11-11T13:58:08.773 回答
2

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

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

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

于 2013-11-10T17:25:03.533 回答
1

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

于 2013-11-10T13:35:47.667 回答