【发布时间】:2018-07-05 21:58:16
【问题描述】:
我有这个 JFace 对话框:
setShellStyle(SWT.APPLICATION_MODAL | SWT.CLOSE);
setBlockOnOpen(false);
有没有办法通过点击对话框外的某个地方来关闭它? 也许像在整个屏幕上监听点击事件并检测它是否在对话框之外,然后关闭。
【问题讨论】:
-
如果你有一个始终相同的底层 gui,你可以添加一个监听器
我有这个 JFace 对话框:
setShellStyle(SWT.APPLICATION_MODAL | SWT.CLOSE);
setBlockOnOpen(false);
有没有办法通过点击对话框外的某个地方来关闭它? 也许像在整个屏幕上监听点击事件并检测它是否在对话框之外,然后关闭。
【问题讨论】:
您可以将SWT.Deactivate 侦听器附加到对话框的底层Shell。
要附加监听器,您可以像这样覆盖Window::configureShell:
@Override
protected void configureShell(Shell shell) {
super.configureShell(shell);
shell.addListener(SWT.Deactivate, event -> shell.close());
}
这里有一个独立的 SWT 示例来说明基本机制:
Display display = new Display();
Shell parentShell = new Shell(display);
parentShell.setSize(500, 500);
parentShell.open();
Shell shell = new Shell(parentShell);
shell.addListener(SWT.Deactivate, event -> shell.close());
shell.setSize(300, 300);
shell.setText("Closes on Deactivate");
shell.open();
while (!parentShell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
【讨论】:
parentShell,子外壳将关闭,如果您单击其他应用程序的外壳,外壳也将关闭。
由于Dialog 是模态的,我相信这会导致使用基本应用程序的Shell 侦听MouseEvents 会带来一些挑战,因为Dialog 会拦截它们。
如果您不反对使用额外的库,您可以考虑使用JNativeHook 来监听全局鼠标点击事件。这将允许您侦听计算机上任何地方的点击,如果点击发生在对话框边界之外,则关闭对话框(如果这是您要查找的内容)。
例如:
GlobalScreen.addNativeMouseListener(new NativeMouseInputAdapter() {
public void nativeMouseClicked(final NativeMouseEvent nativeMouseEvent) {
display.syncExec(new Runnable() {
public void run() {
if (dialog.getShell() == null || dialog.getShell().isDisposed()) {
return;
}
// Close the dialog if there is a mouse click outside the bounds of the dialog
if (!dialog.getShell().getBounds().contains(awtToSwtPoint(nativeMouseEvent.getPoint()))) {
dialog.close();
}
}
});
}
});
除此之外,我不知道有一种方法可以监听基本应用程序之外/屏幕上任何位置的鼠标点击。
完整示例:
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.jnativehook.GlobalScreen;
import org.jnativehook.NativeHookException;
import org.jnativehook.mouse.NativeMouseEvent;
import org.jnativehook.mouse.NativeMouseInputAdapter;
public class DialogCloseTest {
private final Display display;
private final Shell shell;
public DialogCloseTest() {
display = new Display();
shell = new Shell(display);
shell.setSize(450, 450);
final Dialog dialog = new MyDialog(shell);
dialog.open();
registerNativeHook();
GlobalScreen.addNativeMouseListener(new NativeMouseInputAdapter() {
public void nativeMouseClicked(final NativeMouseEvent nativeMouseEvent) {
display.syncExec(new Runnable() {
public void run() {
if (dialog.getShell() == null || dialog.getShell().isDisposed()) {
return;
}
// Close the dialog if there is a mouse click outside the bounds of the dialog
if (!dialog.getShell().getBounds().contains(awtToSwtPoint(nativeMouseEvent.getPoint()))) {
dialog.close();
}
}
});
}
});
}
private org.eclipse.swt.graphics.Point awtToSwtPoint(final java.awt.Point point) {
return new org.eclipse.swt.graphics.Point(point.x, point.y);
}
private static void registerNativeHook() {
try {
GlobalScreen.registerNativeHook();
} catch (NativeHookException ex) {
System.err.println("There was a problem registering the native hook.");
System.err.println(ex.getMessage());
System.exit(1);
}
}
private static void unregisterNativeHook() {
try {
GlobalScreen.unregisterNativeHook();
} catch (NativeHookException e) {
System.err.println("There was a problem unregistering the native hook.");
System.err.println(e.getMessage());
}
}
private static class MyDialog extends Dialog {
MyDialog(final Shell parent) {
super(parent);
}
@Override
protected void configureShell(final Shell shell) {
super.configureShell(shell);
setShellStyle(SWT.APPLICATION_MODAL | SWT.CLOSE);
setBlockOnOpen(false);
}
}
public void run() {
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
unregisterNativeHook();
}
public static void main(String... args) {
new DialogCloseTest().run();
}
}
注意:这将关闭 Dialog,即使它不可见(例如,如果您 alt-tab 离开),因此您可以添加一些逻辑来检查对话框是否也可见,如果您想)
【讨论】: