将JavaFX Stage嵌入到C++ Windows应用程序中

4

通过使用WEmbeddedFrame类,可以轻松地将Java Swing窗口集成到C++应用程序(在Windows上)中:

// (1)
SwingUtilities.invokeLater(() -> {
  try {
    WEmbeddedFrame meinJFrame = new WEmbeddedFrame(hwndParentFromCppApplication);
    meinJFrame.add(... panel ...);
    ...
    meinJFrame.setVisible(true);
  }
  catch (...) {}
});

这似乎可以顺利工作,即使父HWND来自不同的进程。(这是因为Java工程师能够玩弄电锯:http://blogs.msdn.com/b/oldnewthing/archive/2013/04/12/10410454.aspx :-)

据我所知,为了将JavaFX Stage放入本地父窗口中,只有通过将JFXPanel对象包装到Swing WEmbeddedFrame中间接地实现。

// (2)
Platform.runLater(() -> {
    try {
        WEmbeddedFrame frame = new WEmbeddedFrame(hwndParentFromCppApplication);
        final JFXPanel fxPanel = new JFXPanel();
        frame.add(fxPanel);
        frame.setVisible(true);

        Scene scene = ...
        fxPanel.setScene(scene);
        frame.show();
    } catch (...) {}
});

但是这种解决方案有两个严重的缺点:
  • 当鼠标在场景上移动时,场景会闪烁。

  • 在父窗口移动后,组合框项目和菜单项目被放置在错误的位置。

我还尝试将舞台放入一个AppletWindow中:

// (3)
Stage fxstage = new Stage();
fxstage.initStyle(StageStyle.UNDECORATED);
fxstage.setScene(scene);

AppletWindow appw = tk.createAppletWindow(hwndParentFromCppApplication, "");
appw.setStageOnTop(fxstage);
appw.setPosition(0, 0);
appw.setSize(100, 100);
appw.setVisible(true);

// fxstage.show();

这只显示一个黑色矩形。如果我取消注释fxstage.show(),则舞台将作为顶级窗口打开 - 而不是在小程序内部。
在JavaFX源代码中,我找到了com.sun.javafx.stage.EmbeddedWindow类。这听起来很有前途,但我该如何使用它?或者说,我该如何构建所需的HostInterface实现?
您知道如何将JavaFX舞台放入Windows C++窗口吗?
非常感谢!
问候 沃尔夫冈
1个回答

3
根据(2),在与JavaFX源代码进行调试后,我找到了一个解决方案。
  • 将JXPanel包装成JPanel。这可以避免闪烁。
  • 重写JXPanel.setCursor()方法,并调用WEmbeddedFrame.setCursor()。否则,在JavaFX控件中更改光标无效。
  • 将scene.getWindow().setX(), Y, Width, Heigth设置为本机容器窗口的GetClientRect()。这可以在正确的位置显示组合框和菜单项。
但是我仍然有两个问题:

(4) 我不能从JXPanel中获取javafx.stage.Window对象,以将其用作所有者窗口,例如FileChooser。以下代码返回内部使用的Stage对象。但当它被用作所有者时,它不会阻止子窗口。

public Window getWindow() {
    try {
        Class<?> clazz = fxPanel.getClass().getSuperclass();
        Field field = clazz.getDeclaredField("stage");
        field.setAccessible(true);
        Window w = (Window) field.get(fxPanel);
        return w;
    } catch (Throwable e) {
        throw new IllegalStateException("Cannot obtain JavaFX window.");
    }

(5) 当打开一个FileChooser(owner=null)时,UI线程会抛出一个异常。目前,我忽略这个异常,因为它对程序没有任何伤害。

    Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: null source
    at java.util.EventObject.<init>(EventObject.java:56)
    at java.awt.AWTEvent.<init>(AWTEvent.java:337)
    at sun.awt.UngrabEvent.<init>(UngrabEvent.java:48)
    ...
    at com.sun.javafx.stage.WindowPeerListener.focusUngrab(WindowPeerListener.java:105)
    ...
    at com.sun.javafx.tk.quantum.EmbeddedStage.focusUngrab(EmbeddedStage.java:252)
    ...
    at com.sun.javafx.tk.quantum.QuantumToolkit.showFileChooser(QuantumToolkit.java:1421)
    at javafx.stage.FileChooser.showDialog(FileChooser.java:416)
    at javafx.stage.FileChooser.showOpenMultipleDialog(FileChooser.java:373)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接