当前位置: 首页 > 知识库问答 >
问题:

从JFrame中的JFXPanel打开JavaFX子对话框

夏何平
2023-03-14

我正在尝试将第三方JavaFX应用程序嵌入到更大的Swing应用程序中。要求是它的行为就像是一个非模态子窗口。在JavaFX?中如何从JFXPanel打开模态对话框,对我的工作有所帮助?。

但是窗口排序没有正确设置。可以将子舞台放在父JFrame后面。我不会期望这与子窗口。

使用xprop在Ubuntu 16.04中揭示了X11原子WM_TRANSIENT_FOR仅为子JDialog设置,而不是子舞台

示例-打开两个子窗口的应用程序。一个JavaFX和一个Swing。Swing one的父级设置正确。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);
    }
}

共有1个答案

闻昊英
2023-03-14

我最终用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;
}

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

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;
        }
    });
 类似资料:
  • 问题内容: 我的程序应该从文件上传图像,然后将其显示为背景。我的问题是,当我在参数中创建对象时,它会询问您要放入的文件。我试图将我的File对象放入其参数内,但无法正常工作。请帮我。我被卡住了 问题答案: 问题在于,的构造函数期望a ,而您将其传递给a 。任何优秀的IDE都会告诉您给定方法的参数期望值。找到该键盘快捷方式并使用它(IntelliJ中的Ctrl + P)。从那里开始,您所要做的就是找

  • 问题内容: 我需要一种解决方案,以在单击时以HTML显示打开文件对话框。单击时,必须打开打开文件对话框。 我不想将输入文件框显示为HTML页面的一部分。它必须显示在单独的对话框中,该对话框不是网页的一部分。 问题答案: 这是一个不错的 它本身就是一个控件。但是div放在上面,并应用CSS样式来获得那种感觉。文件控件的不透明度设置为0,以便在单击div时似乎打开了对话框窗口。

  • 问题内容: 我试图在弹出新框架时禁用“主” 。我想要它,所以您不能在该框架上单击或拖动任何东西。我尝试将新框架设为a ,但这并没有禁用其他框架。我还查看了有关此的另一篇文章,建议将其设置为a,但仍然无法正常工作。我真的需要帮助。谢谢。这是我正在使用的代码,他们有什么问题吗? 代表“主”框架。 问题答案: 您已经设置了JDialog#setModal或JDialog#ModalityTypes,可能

  • 你好,我正在制作一个简单的桌面应用程序,我正在设计用户界面。我正在使用NetBeans快速设计它。我确实看了很多网站和博客来寻找答案,但是找不到正确的答案。我是UI设计新手。您的答复/建议将不胜感激。 问题是: 我在应用程序中有一个JFrame。这个Jframe有几个JPanel,当用户登录应用程序时,这些JPanel被设置为可见/不可见状态。其中两个面板默认设置为不可见状态(我使用了将它们设置为

  • 我尝试了很多我在网上看到的不同东西,但我什么都做不了。我只需要一个简单的对话框,当你点击菜单中的退出按钮并询问“您确定要退出吗?”并提供一个有效的“是的,我确定。”和“不,取消”按钮。

  • 问题内容: 我想知道是否有跨平台的方法可以从Java Swing应用程序内部模拟Windows“打开方式”对话框。我的应用程序是用于学习软件包的编辑器,并且其中一个用户希望能够在应用程序中从他们选择的编辑器中打开内容文件,资源通常是HTML文件,图像,CSS,JavaScript,但可以是任何类型可以在浏览器中运行的内容。谢谢 问题答案: 我认为您可以使用JDIC(Java桌面集成组件)来做一些事