单击外部关闭SWT shell

时间:2018-01-26 14:32:25

标签: java dialog swt jface

我有这个JFace对话框:

setShellStyle(SWT.APPLICATION_MODAL | SWT.CLOSE);
setBlockOnOpen(false);

有没有办法通过单击对话框外的某个位置来关闭它? 也许就像在整个屏幕上监听点击事件并检测它是否在对话框之外,然后关闭。

2 个答案:

答案 0 :(得分:1)

您可以将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();

答案 1 :(得分:0)

如果01-26 16:43:54.700 1924-1938/com.google.process.gapps E/StrictMode: A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks. java.lang.Throwable: Explicit termination method 'close' not called at dalvik.system.CloseGuard.open(CloseGuard.java:184) at com.google.android.gms.org.conscrypt.Platform.closeGuardOpen(:com.google.android.gms:383) at com.google.android.gms.org.conscrypt.OpenSSLSocketImpl.startHandshake(:com.google.android.gms:297) at com.google.android.gms.org.conscrypt.PreKitKatPlatformOpenSSLSocketImplAdapter.startHandshake(:com.google.android.gms:318) at com.google.android.gms.common.net.SSLCertificateSocketFactory.verifyHostname(:com.google.android.gms:217) at com.google.android.gms.common.net.SSLCertificateSocketFactory.createSocket(:com.google.android.gms:507) at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:197) at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478) at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433) at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290) at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240) at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:81) at libcore.net.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:197) at libcore.net.http.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:281) at com.google.android.gms.http.GoogleHttpClient.a(:com.google.android.gms:943) at com.google.android.gms.http.GoogleHttpClient.a(:com.google.android.gms:761) at com.google.android.gms.http.GoogleHttpClient.execute(:com.google.android.gms:669) at com.google.android.gms.http.GoogleHttpClient.execute(:com.google.android.gms:653) at cyh.a(:com.google.android.gms:233) at dmx.a(:com.google.android.gms:263) at dmx.a(:com.google.android.gms:4235) at dmw.a(:com.google.android.gms:47) at dmq.a(:com.google.android.gms:55) at dmp.a(:com.google.android.gms:113) at com.google.android.gms.auth.account.be.legacy.AuthCronChimeraService.a(:com.google.android.gms:3054) at mwx.run(:com.google.android.gms:179) 01-26 16:43:54.700 1924-1938/com.google.process.gapps E/StrictMode: A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks. java.lang.Throwable: Explicit termination method 'end' not called at dalvik.system.CloseGuard.open(CloseGuard.java:184) at java.util.zip.Inflater.<init>(Inflater.java:82) at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:96) at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:81) at libcore.net.http.HttpEngine.initContentStream(HttpEngine.java:541) at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:844) at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:283) at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:495) at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134) at com.google.android.gms.http.GoogleHttpClient.a(:com.google.android.gms:797) at com.google.android.gms.http.GoogleHttpClient.a(:com.google.android.gms:762) at com.google.android.gms.http.GoogleHttpClient.execute(:com.google.android.gms:669) at com.google.android.gms.http.GoogleHttpClient.execute(:com.google.android.gms:653) at cyh.a(:com.google.android.gms:233) at dmx.a(:com.google.android.gms:263) at dmx.a(:com.google.android.gms:4235) at dmw.a(:com.google.android.gms:47) at dmq.a(:com.google.android.gms:55) at dmp.a(:com.google.android.gms:113) at com.google.android.gms.auth.account.be.legacy.AuthCronChimeraService.a(:com.google.android.gms:3054) at mwx.run(:com.google.android.gms:179) 01-26 16:44:18.310 1924-1924/com.google.process.gapps I/GTalkService/c: [AndroidEndpoint@-1501789600] connect: acct=1000000, state=CONNECTING 01-26 16:44:18.470 1924-1927/com.google.process.gapps D/dalvikvm: GC_CONCURRENT freed 578K, 21% free 4416K/5528K, paused 1ms+2ms, total 11ms 01-26 16:44:18.640 1924-3008/com.google.process.gapps W/Smack/Packet: notify conn break (IOEx), close connection 01-26 16:44:18.900 1924-2308/com.google.process.gapps E/GTalkService: connectionClosed: no XMPPConnection - That's strange! 01-26 16:44:21.640 1580-1661/system_process D/ConnectivityService: handleInetConditionHoldEnd: net=0, condition=0, published condition=0 01-26 16:44:39.660 1580-1648/system_process I/PowerManagerService: Going to sleep by user request... 01-26 16:44:40.080 1113-1188/? D/SurfaceFlinger: Screen released, type=0 flinger=0xb876c6a0 01-26 16:44:40.080 1580-1642/system_process E/libsuspend: Error writing to /sys/power/wakeup_count: Invalid argument 01-26 16:44:40.090 1580-1594/system_process I/WindowManager: No lock screen! 01-26 16:44:40.140 1580-1583/system_process D/dalvikvm: GC_CONCURRENT freed 1870K, 51% free 9918K/20160K, paused 2ms+1ms, total 15ms 01-26 16:44:40.140 1580-1593/system_process D/dalvikvm: WAIT_FOR_CONCURRENT_GC blocked 4ms 01-01 00:00:00.000 0-0/? E/Internal: device 'emulator-5554' not found 是模态的,我认为使用基础应用程序的Dialog来监听Shell会导致一些挑战,因为MouseEvent会拦截它们。

如果您不反对使用其他库,可以考虑使用JNativeHook来监听全局鼠标点击事件。这将允许您在计算机上侦听单击任何地方,如果单击发生在对话框边界之外,则关闭对话框,如果这正是您要查找的内容。

例如:

Dialog

除此之外,我不知道如何在屏幕上的任何地方收听基本应用程序之外的鼠标点击。

完整示例:

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(); } } ,即使它不可见(例如,如果你alt-tab远离),所以你可以添加一些逻辑来检查对话框是否也可见,如果你愿意的话)