【问题标题】:Open JavaFX child dialog from JFXPanel within JFrame从 JFrame 中的 JFXPanel 打开 JavaFX 子对话框
【发布时间】:2016-12-31 10:44:29
【问题描述】:

我正在尝试将第三方 JavaFX 应用程序嵌入到更大的 Swing 应用程序中。要求是它的行为就好像它是一个非模态子窗口。 How to open modal dialog from JFXPanel in JavaFX? 帮助我完成了这项工作。

但是窗口排序设置不正确。可以将子 Stage 放在父 JFrame 后面。我不希望有一个子窗口。

在 Ubuntu 16.04 中使用 xprop 显示 X11 Atom WM_TRANSIENT_FOR 仅为子 JDialog 设置,而不是子 Stage

示例 - 打开两个子窗口的应用。一个 JavaFX 和一个 Swing。 Swing 是正确的父级。 JavaFX 不是。

public class SwingApp {

    public static void main(String[] args) throws Exception {
        JFrame parent = new JFrame();
        parent.setTitle("Parent JFrame");
        parent.setSize(200, 150);
        JFXPanel jfxPanel = new JFXPanel();
        parent.getContentPane().setLayout(new BoxLayout(parent.getContentPane(), BoxLayout.Y_AXIS));
        JButton button = new JButton("Open Swing child");
        button.addActionListener(e -> {
            JDialog child = new JDialog(parent);
            child.setModal(false);
            child.getContentPane().add(new JLabel("content"));
            child.setVisible(true);
        });
        parent.getContentPane().add(button);
        parent.getContentPane().add(jfxPanel);
        parent.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        parent.setVisible(true);

        Platform.runLater(() -> jfxPanel.setScene(new Scene(createDummyFxApp(jfxPanel))));
    }

    private static Parent createDummyFxApp(JFXPanel openingPanel) {
        Button button = new Button("Open FX child");
        button.setOnAction(e -> {
            Stage stage = new Stage();
            stage.initModality(Modality.NONE);

            Window owner = openingPanel.getScene().getWindow();
            stage.initOwner(owner);

            stage.setTitle("Non-modal child JavaFX window");
            stage.setScene(new Scene(new HBox(new Label("content"))));
            stage.show();
        });

        return new HBox(button);
    }
}

【问题讨论】:

    标签: java swing javafx javafx-8


    【解决方案1】:

    我最终通过 JNA 实现了这一点。首先按标题找到窗口。

    public List<Window> find(Pattern title) {
        Display display = x11.XOpenDisplay(null);
        Window root = x11.XDefaultRootWindow(display);
        List<Window> windows = recurse(x11, display, root, title);
        x11.XCloseDisplay(display);
        return windows;
    }
    
    private synchronized List<Window> recurse(X11 x11, Display display, Window root, Pattern pattern) {
        List<Window> windows = new ArrayList<>(1);
        X11.WindowByReference windowRef = new X11.WindowByReference();
        X11.WindowByReference parentRef = new X11.WindowByReference();
        PointerByReference childrenRef = new PointerByReference();
        IntByReference childCountRef = new IntByReference();
    
        x11.XQueryTree(display, root, windowRef, parentRef, childrenRef, childCountRef);
        if (childrenRef.getValue() == null) {
            return Collections.emptyList();
        }
    
        long[] ids;
    
        if (Native.LONG_SIZE == Long.BYTES) {
            ids = childrenRef.getValue().getLongArray(0, childCountRef.getValue());
        } else if (Native.LONG_SIZE == Integer.BYTES) {
            int[] intIds = childrenRef.getValue().getIntArray(0, childCountRef.getValue());
            ids = new long[intIds.length];
            for (int i = 0; i < intIds.length; i++) {
                ids[i] = intIds[i];
            }
        } else {
            throw new IllegalStateException("Unexpected size for Native.LONG_SIZE" + Native.LONG_SIZE);
        }
    
        for (long id : ids) {
            Window child = new Window(id);
            X11.XTextProperty name = new X11.XTextProperty();
            int result = x11.XGetWMName(display, child, name);
            String value = name.value;
            LOGGER.info(String.format("Found window %s result: %d free %s", value, result, name));
    
            if (value != null && pattern.matcher(value).matches()) {
                windows.add(child);
            }
            windows.addAll(recurse(x11, display, child, pattern));
        }
        return windows;
    }
    

    然后,通过添加 atom 的瞬态来“采用”窗口

    public void adopt(Window child, Window parent) {
        Display display = x11.XOpenDisplay(null);
    
        Atom wmState = x11.XInternAtom(display, "_NET_WM_STATE", false);
        Atom wmStateModal = x11.XInternAtom(display, "_NET_WM_STATE_MODAL", false);
        x11.XSetTransientForHint(display, child, parent);
        addAtom(display, child, wmState, wmStateModal);
    
        x11.XCloseDisplay(display);
    
    }
    

    使用这种支持方式

    public void addAtom(Display display, Window win, Atom key, Atom value) {
    
        int maskVal = X11.SubstructureRedirectMask | X11.SubstructureNotifyMask;
        NativeLong mask = new NativeLong(maskVal);
    
        XClientMessageEvent event = new X11.XClientMessageEvent();
        event.type = X11.ClientMessage;
        event.serial = new NativeLong(0);
        event.send_event = 1;
        event.message_type = key;
        event.window = win;
        event.format = 32;
        event.data.setType(NativeLong[].class);
        event.data.l[0] = new NativeLong(NET_WM_STATE_ADD);
        event.data.l[1] = value;
        event.data.l[2] = new NativeLong(0);
        event.data.l[3] = new NativeLong(0);
        event.data.l[4] = new NativeLong(0);
    
        X11.XEvent e = new X11.XEvent();
        e.setTypedValue(event);
    
        x11.XSendEvent(display, x11.XDefaultRootWindow(display), 0, mask, e);
        x11.XFlush(display);
    
    }
    

    还必须向 X11 添加错误处理程序,否则默认错误处理程序会使 VM 崩溃,当尝试获取自最初发现以来已消失的窗口的信息时会发生这种情况。

       x11.XSetErrorHandler(new XErrorHandler() {
            @Override
            public int apply(Display display, XErrorEvent errorEvent) {
                LOGGER.warn(String.format("X11 error during JNA, ignore for now: %s", errorEvent.toString()));
                return 0;
            }
        });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-14
      • 2012-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多