2012-04-19 22 views
5

Tengo una aplicación con una clase abstracta que se extiende JDialog. La clase como un abstract void onClose(), y, en el constructor de la clase, se añade el siguiente código:`WindowListener` actuando, despido perpetuo

addWindowListener(new WindowAdapter() { 
    @Override 
    public void windowClosed(WindowEvent e) { 
     onClose(); 
    } 
} 

El evento se activa cuando se esperaba, pero luego sucede algo extraño. Cuando una extensión concreta de esta clase tiene código para crear un nuevo JDialog en el método onClose(), y JDialogdefaultCloseOperation es JDialog.DISPOSE_ON_CLOSE, el evento se dispara continuamente, hasta que fuerzo salir de la operación.

He aislado el código para la siguiente SSCCE:

// package removed 
// imports removed 
public class SSCCE extends JDialog { 
    public static void main(String[] args) { 
     SSCCE s = new SSCCE(); 
     s.pack(); 
     s.setVisible(true); 
    } 
    public SSCCE() { 
     setLayout(new GridLayout(1, 0, 0, 0)); 
     JButton btn = new JButton("click me"); 
     btn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       dispose(); 
      } 
     }); 
     addWindowListener(new WindowAdapter() { 
      @Override 
      public void windowClosed(WindowEvent e) { 
       System.out 
         .println("SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()"); 
       onClose(); 
      } 
     }); 
     add(btn); 
    } 

    public void onClose() { 
     JDialog dialog = new JDialog(); 
     dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 
     dialog.setVisible(true); 
    } 

} 

Al hacer clic en el botón "Me clic", la pieza en bruto JDialog aparece y SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed() aparece en la ventana de la consola. Cuando cierro el cuadro de diálogo en blanco, vuelve a aparecer y el texto aparece de nuevo.

Otra cosa muy interesante es que cuando cambio la línea de inicialización de

JDialog dialog = new JDialog(); 

a

JDialog dialog = new JDialog() { 
     @Override 
     public synchronized void addWindowListener(WindowListener l) { 
      super.addWindowListener(l); 
      System.out 
        .println("SSCCE.onClose().new JDialog() {...}.addWindowListener()"); 
     } 
    }; 

Me da la siguiente salida en la consola:

Al hacer clic en el "clic yo "botón:

SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 

En el primer cierre de la ventana de diálogo:

SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 

En el segundo cierre del diálogo:

SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 
SSCCE.onClose().new JDialog() {...}.addWindowListener() 

Cada vez que cierro la ventana de diálogo, addWindowListener(WindowListener l) se llama un adicional tiempo, aunque no lo estoy llamando intencionalmente.

que realmente no quieren ningún WindowListener s para ser registrados en el diálogo, pero creo que simplemente reemplazando el método addWindowListener(...) y no llamar super.addWindowListener(...) sería demasiado descuidado.

Estoy ejecutando Java 1.6.0_31 en Mac OS X 10.6.8, utilizando Eclipse Indigo (con WindowBuilder, si es importante).

¿Alguien tiene alguna idea?

Gracias!

Respuesta

7

Como por el Java Dialog tutorial,

Cada diálogo es dependiente de un componente de tramas. Cuando ese Marco se destruye, también lo son sus Diálogos dependientes.

Cuando se utiliza la JDialog constructor without any arguments, que

Crea un diálogo no modal sin título y sin dueño de un marco determinado. Se establecerá un marco compartido y oculto como propietario del cuadro de diálogo.

que compartían marco oculto es SwingUtilities$SharedOwnerFrame, y en la inicialización se registra una WindowListener a todas las ventanas de propiedad.

Cuando cierra el diálogo, el SharedOwnerFrame 's windowClosed método se llama, que comprueba todas las ventanas de su propiedad (en este punto es el diálogo SSCCE original y la nueva), no encuentra ninguno son visibles, y por lo tanto se deshace Esto tiene el impacto de eliminar todos los cuadros de diálogo que posee, lo que publica un evento de cierre de ventana para cada uno. Esto llama al windowClosed en su oyente, abriendo un nuevo cuadro de diálogo. Y a la vuelta vamos de nuevo :-). En cuanto a sus últimos comentarios, obtiene líneas de registro adicionales cada vez porque obtiene uno por diálogo que posee el SharedOwnerFrame.

Si realiza el diálogo SSCCE propia el nuevo cuadro de diálogo (pasando this en su constructor), entonces no es terminar con la propiedad compartida y funciona bien:

public void onClose() { 
    JDialog dialog = new JDialog(this); 
    dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 
    dialog.setVisible(true); 
} 
+0

Gracias! Eso tiene perfecto sentido. – wchargin

4
import java.awt.GridLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 

import javax.swing.JButton; 
import javax.swing.JDialog; 
import javax.swing.JOptionPane; 

public class SSCCE extends JDialog { 
    public static void main(String[] args) { 
     SSCCE s = new SSCCE(); 
     s.pack(); 
     s.setVisible(true); 
    } 

    private WindowAdapter wa = new WindowAdapter() { 
     @Override 
     public void windowClosed(WindowEvent e) { 
      System.out 
        .println("SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()"); 
      onClose(); 
     } 
    }; 

    public SSCCE() { 
     setLayout(new GridLayout(1, 0, 0, 0)); 
     JButton btn = new JButton("click me"); 
     btn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       dispose(); 
      } 
     }); 
     addWindowListener(
     wa); 
     add(btn); 
    } 

    public void onClose() { 
     removeWindowListener(wa); 
     JDialog dialog = new JDialog(); 
     dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 
     dialog.setVisible(true); 

    } 

} 
+0

Veo lo que usted' he terminado, y veo por qué funciona, pero realmente me pregunto por qué el oyente ('wa') se está agregando a' dialog' en primer lugar. ¿Podrías explicarme por qué? – wchargin

+0

Ojalá tuviera una buena respuesta para ti. Creo que puede tener que ver con el hecho de que su clase extiende JDialog. – ControlAltDel

+0

user1291492 'con el hecho de que su clase extiende JDialog' +++++ 1k, exactamente – mKorbel

Cuestiones relacionadas