Как закрыть модальный JDialog при нажатии пользователем вне JDialog?

У меня есть Undecorated Modal JDialog, который я хочу установить. (false), когда пользователь щелкает за пределами модального диалога.

Возможно ли это в Swing?

То, что я делаю, это вывести пользовательский редактор для текстового поля, такого как селектор даты. Есть ли более простой способ сделать то, что я хочу?

ИЗМЕНИТЬ

Помните, что модальные блоки при вызове setVisible (true), поэтому вы не можете просто сказать "не использовать модальный диалог"

И я пробовал прослушивать фокус-слушатели в диалоговом окне, они не запускаются, когда его модальные.

7 ответов

Это не модальный диалог, если вы можете щелкнуть его, а "что-то" произойдет. Все ответы верны, вы должны создать немодальный диалог, а затем обработать свой прецедент через FocusListener.


EDIT: Изменен для использования WindowFocusListener вместо FocusListener, а также проверьте, чтобы нисходящие компоненты потеряли фокус, чтобы не скрыть, если дочерний компонент получает фокус.

Простым способом было бы добавить прослушиватель окна в диалог, который скрывает его, когда фокус потерян. В этом случае я не вижу необходимости в модальности. Например:

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); 
 }
 });
 }
}


Попробуйте установить модальное значение false, а затем используйте windowDeactivated() для закрытия диалогового окна (dialog.dispose()), работает для меня.


Не обязательно быть модальным диалогом (модальный означает, что он не позволяет вам использовать окно владельца, пока вы не скроете диалог). Лучше попробуйте следующее:

final JDialog dlg ...
dlg.setModal(false);
dlg.addWindowFocusListener(new WindowFocusListener() { 
 public void windowLostFocus(WindowEvent e) {
 dlg.setVisible(false);
 } 
 public void windowGainedFocus(WindowEvent e) {
 }
});


Не модальный диалог, а затем, если вы нажмете else, где он закрывается, возможно, вы хотите setAlwaysOnTop

Однако, что-то вроде следующего должно сделать трюк (непроверенный). Заметьте, я бы рекомендовал переместить код в нечто более совершенное, чем использовать, как предусмотрено.

static JDialog dialog = ...
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
 public void eventDispatched(AWTEvent e) {
 dialog.setVisible(false);
 SwingUtils.invokeLater(new Runnable(){
 public void run(){
 Toolkit.getDefaultToolkit().removeAWTEventListener(this);
 }
 }); 
 }
}, AWTEvent.MOUSE_EVENT_MASK);
dialog.setVisible(true);


Возможно, добавьте FocusListener и скройте диалог, когда он потеряет фокус. Может быть сложно, если некоторые элементы в диалоговом окне могут иметь фокус. В любом случае, экспериментируйте с ним.


Используйте WindowListener и обработайте событие windowDeactivated().

licensed under cc by-sa 3.0 with attribution.