1

JavaFx 应该很容易集成到 SWT 应用程序中(参见此处:http ://docs.oracle.com/javafx/2/swt_interoperability/jfxpub-swt_interoperability.htm ),并且两个工具包都使用相同的线程模型。

但是,当我打开一个包含 FxCanvas 的对话框时,事情变得很奇怪,其中包含一个 JavaFx ComboBox。如果我打开组合框弹出菜单然后关闭对话框,弹出菜单将保持打开状态。如果我现在将鼠标移动到弹出窗口上,则会在 javafx 中引发空指针异常。在较大的应用程序中执行此操作时,所有 JavaFx GUI 将保持损坏,直到重新启动应用程序。

在此处输入图像描述

有什么办法可以解决这个问题?

下面的示例代码:使用“确定”或窗口关闭按钮关闭对话框。使用“取消”退出应用程序

package test;

import javafx.embed.swt.FXCanvas;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.StackPane;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class TestFx {
    static class MyDialog extends Dialog {
        Parent w;
        public MyDialog(Shell parent,Parent n) {
            super(parent);
            this.w = n;
            setShellStyle(SWT.RESIZE| SWT.BORDER | SWT.TITLE |SWT.CLOSE );
        }
        @Override
        public void cancelPressed() {
            System.exit(0);
        }
        @Override
        protected Control createDialogArea(Composite parent) {
            Composite container = (Composite) super.createDialogArea(parent);
            container.setLayout(new FillLayout());
            FXCanvas fxCanvas = new FXCanvas(container, SWT.NONE);
            Scene scene = new Scene(w);
            fxCanvas.setScene(scene);
            return container;
        }
    }

    private static Parent createScene() {
        StackPane pane = new StackPane();
        pane.setPadding(new Insets(10));
        ComboBox<String> c = new ComboBox<String>();
        c.getItems().addAll("Test1","Test2");
        pane.getChildren().add(c);
        return pane;
    }

    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        while (true) {
            MyDialog d  = new MyDialog(shell,createScene());
            d.open();
        }
    }
}

例外:

java.lang.NullPointerException
    at com.sun.javafx.tk.quantum.GlassScene.sceneChanged(GlassScene.java:290)
    at com.sun.javafx.tk.quantum.ViewScene.sceneChanged(ViewScene.java:156)
    at com.sun.javafx.tk.quantum.PopupScene.sceneChanged(PopupScene.java:30)
    at com.sun.javafx.tk.quantum.GlassScene.markDirty(GlassScene.java:157)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2214)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:363)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:460)
    at com.sun.javafx.tk.quantum.QuantumToolkit$9.run(QuantumToolkit.java:329)
    at org.eclipse.swt.internal.win32.OS.DispatchMessageW(Native Method)
    at org.eclipse.swt.internal.win32.OS.DispatchMessage(OS.java:2546)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3756)
    at org.eclipse.jface.window.Window.runEventLoop(Window.java:825)
    at org.eclipse.jface.window.Window.open(Window.java:801)
    at test.TestFx.main(TestFx.java:55)
4

3 回答 3

1

我在使用 Java7 时找到了一种解决方法:覆盖 Dialog 中的 close 方法以隐藏组合框弹出窗口:

@Override
public boolean close() {
    Set<Node> nodes = w.lookupAll("#");
    for (Node n : nodes)
        if (n instanceof ComboBox)
            ((ComboBox)n).hide();
    return super.close();
}
于 2013-06-07T22:25:47.210 回答
1

在工作中,我们正在使用 JavaFX 在旧的 Swing 平台上开发一些应用程序,我们也发现了这个问题。

显然这是由 JFXPanel 上的一些问题引起的,这些问题没有正确地将某些窗口事件(焦点、图标化等)传播到 FX 框架。该问题不仅影响 ComboBox 组件,还影响使用 PopupWindow(菜单、工具提示等)的每个组件,尤其是在使用 Swing 的 JInternalFrame 时。

因此,当弹出窗口正在显示并且窗口被最小化或关闭时,弹出窗口不会隐藏,如果您随后尝试与之交互,则会导致 FX 线程崩溃。

上面提到的解决方法有效,但仅适用于 ComboBox,因为 Menu 和 Tooltip 不继承自 Node 类,所以对我们不起作用:(

我开发了另一种解决方法,它解决了所有显示弹出窗口的组件的问题,它基本上强制所有弹出窗口在 JFXPanel 失去焦点时关闭:

private static void initFX(final JFXPanel jfxPanel) {
  final TestFxPanel parent = new TestFxPanel();
  final Scene scene = new Scene(parent);
  jfxPanel.setScene(scene);

  jfxPanel.addFocusListener(new FocusAdapter() {

  @Override
    public void focusLost(final FocusEvent e) {
      System.out.println(jfxPanel.getName() + ": FocusLost");
      runFocusPatch(scene);
    }
  });
}

static void runFocusPatch(final Scene scene) {
  Platform.runLater(new Runnable() {

    @Override
    public void run() {
      System.out.println("Running patch");

      final Iterator<Window> winIter = scene.getWindow().impl_getWindows();
      while (winIter.hasNext()) {
        final Window t = winIter.next();
        if (t instanceof PopupWindow) {
          System.out.println("Got a popup");
          Platform.runLater(new Runnable() {
            @Override
            public void run() {
              ((PopupWindow) t).hide();
            }
          });
        }
      }
    }
  });
}

我确认该问题在 8.0 中不存在。遗憾的是,我们不允许在生产软件中使用 java 8,因为它仍处于 beta 阶段。

最好的祝福。

于 2013-11-26T15:25:42.350 回答
0

问题在这里讨论:javafx-jira.kenai.com/browse/RT-30991

开发人员表示,该问题已在 JavaFX-8 中修复

于 2013-06-07T21:23:19.850 回答