With the Dialog
being modal I believe that causes some challenges using the Shell
of the base application to listen for MouseEvent
s because the Dialog
intercepts them.
If you're not opposed to using an additional library you could consider using JNativeHook to listen for global mouse click events. This would allow you to listen for a click anywhere on the computer and close the dialog if the click occurred outside the dialog bounds, if that's what you're looking for.
For example:
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();
}
}
});
}
});
Other than that, I'm not aware of a way to listen to mouse clicks that are outside of the base application / anywhere on the screen.
Full example:
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();
}
}
Note: This will close the Dialog
even if it is not visible (eg. if you alt-tab away), so you could add some logic to check whether the dialog is visible as well, if you would like)