【问题标题】:Close SWT shell by clicking outside of it通过单击外部关闭 SWT shell
【发布时间】:2018-07-05 21:58:16
【问题描述】:

我有这个 JFace 对话框:

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

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

【问题讨论】:

  • 如果你有一个始终相同的底层 gui,你可以添加一个监听器

标签: java dialog swt jface


【解决方案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();

【讨论】:

  • 对话框外点击好像没有触发Deactivate事件
  • 我无法重现您所描述的内容。您究竟是在哪里点击在对话框之外的?我添加了一个简单的 SWT 示例。如果您单击parentShell,子外壳将关闭,如果您单击其他应用程序的外壳,外壳也将关闭。
  • 在触摸屏上,当单击子(已启用)复合材料时,外壳也会停用,因此此方法不会真正起作用。 !
【解决方案2】:

由于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 离开),因此您可以添加一些逻辑来检查对话框是否也可见,如果您想)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-20
    • 2021-11-24
    • 1970-01-01
    • 2018-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多