我正在尝试在更大的Swing应用程序中嵌入第三方JavaFX应用程序。要求是它的行为就好像它是一个非模态子窗口。我有点帮助How to open modal dialog from JFXPanel in JavaFX?。
但是窗口排序设置不正确。可以将子Stage放在父JFrame后面。我不希望这有一个子窗口。
使用xprop在Ubuntu 16.04中显示X11 Atom WM_TRANSIENT_FOR仅为子JDialog设置,而不是子Stage
示例 - 打开两个子窗口的应用程序。一个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);
}
}
答案 0 :(得分:0)
我最终通过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;
}
然后,&#34;采用&#34;窗口通过添加瞬态原子
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;
}
});