Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Embedding JavaFX Stage into C++ Windows Application

A Java Swing window can be easily integrated into a C++ application (on Windows) by using the WEmbeddedFrame class:

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

It seems to work smoothly, even though the parent HWND comes from a different process. (This is because the Java engineers are able to juggle chainsaws: http://blogs.msdn.com/b/oldnewthing/archive/2013/04/12/10410454.aspx :-)

As far as I could investigate, in order to put a JavaFX Stage into a native parent window, only an indirect way is possible with JFXPanel object wrapped into a 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 (...) {}
});

But this solution has two serious disadvantages:

  • The scene is flickering when moving the mouse over it.

  • The combobox items and menu items are placed at the wrong position after the parent window has been moved.

I also tried to put the Stage into an 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();

This shows only a black rectangle. If I uncomment fxstage.show(), the stage is opened as a toplevel window - not inside the applet.

In the JavaFX sources, I found the class com.sun.javafx.stage.EmbeddedWindow. It sounds promising, but how do I use it? Resp. how do I construct the required HostInterface implementation?

Do you know how to put a JavaFX stage into a Windows C++ window?

Many thanks in advance!

Regards Wolfgang

like image 582
wimix Avatar asked Oct 18 '25 00:10

wimix


1 Answers

Based on (2), I found a solution after spending days with debugging inside JavaFX source.

  • Wrap the JXPanel into a JPanel. This stops flickering.
  • Overwrite JXPanel.setCursor() and call WEmbeddedFrame.setCursor(). Otherwise, changing the cursor in JavaFX controls has no effect.
  • Set scene.getWindow().setX(), Y, Width, Heigth to the GetClientRect() of the native container window. This shows the combobox and menu items at the correct position.

But I still got two problems:

(4) I cannot get a javafx.stage.Window object from the JXPanel which can be used as an owner window e.g. for the FileChooser. The following code returns the internally used Stage object. But when used as an owner, it does not block the child windows.

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) When opening a FileChooser (owner=null) an exception is thrown in the UI thread. Currently, I ignore the exception because it does not harm anything.

    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)
like image 50
wimix Avatar answered Oct 19 '25 12:10

wimix