2009-11-04 18 views
5

Tengo un JDialog modal no decorado que quiero establecer Visible (falso) cuando el usuario hace clic fuera del cuadro de diálogo modal.¿Cómo cerrar un JDialog modal cuando el usuario hace clic fuera de JDialog?

¿Esto es posible en Swing?

Lo que estoy haciendo es abrir un editor personalizado para un campo de texto como un selector de fecha. ¿Hay una manera más fácil de hacer lo que quiero?

EDITAR

Recuerde que los bloques modales en la llamada a setVisible (verdadero), por lo que no puede decir "no utilice un diálogo modal"

y he tratado de enfoque oyentes en el diálogo, no se disparan cuando es modal.

+0

¿Has probado el método addAWTEventListener, esto debería darte eventos para todos los tipos de eventos especificados, p. en el ejemplo que dí a continuación, serían todos los eventos del mouse. – vickirk

+0

Sé que dijiste "por lo que no puedes decir" no usar un cuadro de diálogo modal "", presumiblemente porque tienes un código que se ejecuta inmediatamente después de la llamada a setVisible. ¿No podrías mover esto a un oyente para cuando el diálogo esté cerrado? Sin conocer los detalles de su aplicación puede proporcionar un diseño más limpio, especialmente cuando se trata de pruebas unitarias, me gusta mover los diálogos a una estrategia para obtener respuestas de los usuarios, de esa manera puedo inyectar estrategias simuladas sin colgar una prueba unitaria cuando se ejecuta sin cabeza o sin tener que perder el tiempo creando eventos programáticamente. – vickirk

Respuesta

3

No es un cuadro de diálogo modal si puede hacer clic fuera de él y ocurre "algo". Todas las respuestas son correctas, debería crear un diálogo no modal y luego tratar su caso de uso a través de un FocusListener.

+0

Esta es la respuesta más cercana a "No". Eso es todo lo que estaba preguntando. No cómo puedo lograr esto sin un diálogo no modal. – Pyrolistical

0

No es realmente un diálogo modal a continuación, hacer clic en otro lado si lo cierra, tal vez usted quiere setAlwaysOnTop

Sin embargo, algo así como lo siguiente debe hacer el truco (no probado). Tenga en cuenta que recomendaría mover el código a algo mejor diseñado que usarlo como se indica.

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); 
+0

Acabo de probar esto y parece que este tipo de oyente tampoco recibe ningún evento del mouse fuera del diálogo modal. – Zalumon

0

Probablemente añadir un FocusListener y ocultar el diálogo cuando se pierde el foco. Puede ser complicado si algunos elementos en el diálogo pueden tener foco. De todos modos, experimenta con eso.

+0

¿Puede un diálogo modal (y componentes secundarios) perder el foco para otra cosa que no sea cambiar a otra aplicación? – vickirk

+0

¡Ah, entiendes lo que quieres decir, quisiste decir en vez de un diálogo modal! No sé por qué se votó negativamente – vickirk

10

EDIT:cambiado para usar en lugar de WindowFocusListener FocusListener, así como de verificación de componentes descendente en el foco perdido con el fin de no ocultar si un componente gana niño se centran.

Una manera simple sería añadir un oyente ventana de enfoque en el diálogo que se esconde cuando se pierde el foco. No veo la necesidad de una modalidad en este caso. Por ejemplo:

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

El foco perdido debería garantizar que el componente que ganó el foco no es un componente secundario del diálogo, por lo que deberá buscar la jerarquía del componente a través de 'getParent()' – vickirk

+0

@vickirk - - buen punto. Cambié el ejemplo anterior para buscar componentes descendientes (posiblemente un caso marginal, pero mejoré el ejemplo para permitir la creación de una ventana secundaria del diálogo). También lo cambié para usar un oyente de enfoque de ventana. –

+0

Sí, entiendo totalmente cómo se puede hacer esto sin un diálogo modal, pero el objetivo de la pregunta era si era posible hacerlo con un cuadro de diálogo modal. La principal ventaja de usar un diálogo modal es que bloquea cuando setVisible (verdadero). Mi objetivo era no tener que reestructurar el programa para usar un diálogo no modal o escribir una utilidad para emular la naturaleza de bloqueo en un diálogo no modal. – Pyrolistical

0

Utilice un WindowListener y maneje el evento windowDeactivated().

+0

Acabo de probar esto y para mí este enfoque solo pareció funcionar al hacer clic completamente fuera de la aplicación java, pero no al intentar hacer clic en el marco principal de java que generó el cuadro de diálogo modal. – Zalumon

+0

@Zalumon, supongo que esta respuesta no fue muy clara. Esta fue una sugerencia para NO usar un JDialog modal. Cuando utiliza un JDialog modal como ventana emergente, no puede cerrar el cuadro de diálogo si hace clic fuera del cuadro de diálogo. Esta es una solución que le permite cerrar un 'diálogo no modal' cuando hace clic fuera del área de diálogo, por lo que el" diálogo emergente "se cierra. – camickr

1

No es necesario que sea un cuadro de diálogo modal (modal significa que le impide utilizar la ventana del propietario hasta que oculte el cuadro de diálogo). Mejor prueba esto:

final JDialog dlg ... 
dlg.setModal(false); 

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

intenta establecer el referente a falso, y luego usar windowsDeactivated() por cerca de diálogo (dialog.dispose()), funciona para mí.

Cuestiones relacionadas