How to close a modal JDialog when user clicks outside of JDialog?
Solution 1
It's not a modal dialog if you can click outside of it and "something" happens. All the answers are correct, you should be creating a non-modal dialog and then deal with your use case via a FocusListener.
Solution 2
EDIT: Changed to use WindowFocusListener instead of FocusListener, as well as check for descending components on the focus lost in order to not hide if a child component gains focus.
A simple way would be to add a window focus listener on the dialog that hides it when focus is lost. I don't see the need for modality in this case. For example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ClickAwayDialog extends JDialog {
public ClickAwayDialog(final Frame owner) {
super(owner);
JPanel pnl = new JPanel(new BorderLayout());
pnl.add(new JLabel("Click outside this dialog in the parent frame to close it"), BorderLayout.NORTH);
JButton btn = new JButton("Click Me");
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(ClickAwayDialog.this, "New Child Window");
}
});
pnl.add(btn, BorderLayout.CENTER);
this.setContentPane(pnl);
this.pack();
this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
this.setLocationRelativeTo(owner);
this.setAlwaysOnTop(true);
this.addWindowFocusListener(new WindowFocusListener() {
public void windowGainedFocus(WindowEvent e) {
//do nothing
}
public void windowLostFocus(WindowEvent e) {
if (SwingUtilities.isDescendingFrom(e.getOppositeWindow(), ClickAwayDialog.this)) {
return;
}
ClickAwayDialog.this.setVisible(false);
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame parent = new JFrame();
parent.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
parent.setSize(300, 300);
parent.setLocationByPlatform(true);
parent.setVisible(true);
ClickAwayDialog dlg = new ClickAwayDialog(parent);
dlg.setVisible(true);
}
});
}
}
Solution 3
Try to set the modal to false, and then use windowsDeactivated() for close de dialog (dialog.dispose()), works for me.
Solution 4
It's not necessary to be a modal dialog (modal means that it prevents you from using the owner window until you hide the dialog). Better try this:
final JDialog dlg ...
dlg.setModal(false);
dlg.addWindowFocusListener(new WindowFocusListener() {
public void windowLostFocus(WindowEvent e) {
dlg.setVisible(false);
}
public void windowGainedFocus(WindowEvent e) {
}
});
Solution 5
Use a WindowListener and handle the windowDeactivated() event.
Related videos on Youtube
Pyrolistical
Premature optimization is the root of all evil If you are not trying to learn all the time, then you are not a great developer User input is sacred
Updated on June 04, 2022Comments
-
Pyrolistical almost 2 years
I have a Undecorated Modal JDialog which I want to setVisible(false) when the user clicks outside of the modal dialog.
Is this possible in Swing?
What I am doing is popping up a custom editor for a text field like a date selector. Is there an easier way to do what I want?
EDIT
Remember that modal blocks on the call to setVisible(true), so you can't just say "don't use a modal dialog"
And I've tried focus listeners on the dialog, they don't trigger when its modal.
-
vickirk over 14 yearsDid you try the addAWTEventListener method, this should give you events for all specified event types, e.g. in the example I gave below this would be all mouse events.
-
vickirk over 14 yearsI know you said "so you can't just say "don't use a modal dialog"", presumably this is because you have code that executes straight after the setVisible call? Could you not move this into maybe a listener for when the dialog is closed? Without knowing details of your app it may provide a cleaner design, especially when it comes to unit testing, I like to move dialogs out into a strategy for getting user responses, that way I can inject mock strategies without hanging a unit test when it runs headless or without having to mess around with creating events programatically.
-
-
vickirk over 14 yearsCan a modal dialog (and child components) loose focus for anything other than switching to another application?
-
vickirk over 14 yearsAh, got what you mean, you meant instead of a modal dialog! Don't know why this was voted down
-
vickirk over 14 yearsFocus lost would have to ensure the component that gained the focus is not a child component of the dialog so you will need to search up the component hierarchy via
getParent()
-
Chris B. over 14 years@vickirk -- good point. I changed the example above to check for descendant components (arguably an edge case, but I enhanced the example to allow creating a child window of the dialog). I also changed it to use a window focus listener.
-
Pyrolistical over 12 yearsYes I totally understand how one can do this without a modal dialog, but the point of the question was if it was possible to do it with a modal dialog. The main advantage of using a modal dialog is it blocks when setVisible(true). My goal was to not need to restructure the program to use a non-modal dialog or write a utility to emulate the blocking nature in a non-modal dialog.
-
Pyrolistical over 12 yearsThis is the closest answer to "No". That's all I was asking. Not how I can achieve this without a non-modal dialog.
-
Reto Höhener almost 9 yearsI just tested this and it looks like this kind of listener also does not get any mouse events from outside the modal dialog.
-
Reto Höhener almost 9 yearsI just tested this and for me this approach only seemed to work when clicking completely outside of the java application, but not when trying to click on the java main frame that spawned the modal dialog.
-
camickr almost 9 years@Zalumon, I guess this answer was not very clear. This was a suggestion to NOT use a modal JDialog. When you use a modal JDialog as a popup, then you can't close the dialog if you click outside the dialog. This is a solution to allow you to close a
non modal dialog
when you click outside the dialog area, so the "popup dialog" gets closed.