JDialog desde un ActionEvent

De ChuWiki

Para evitar que la carga inicial de nuestro programa se alargue mucho, se puede retrasar la construcción de las ventanas secundarias hasta que no sean necesarias. Puede ser una técnica bastante habitual crear la ventana secundaria la primera vez que se pulsa el botón que la despliega.

Otro asunto interesante de esta técnica es que en el ActionEvent de la pulsación del botón viene el botón que ha sido pulsado. A partir de este botón podemos obtener quién será la ventana padre del JDialog que vamos a desplegar, de forma que este JDialog no se vaya detrás de su ventana padre. La ventana padre será, en principio, la que contiene al botón.

Veamos todo esto con un código de ejemplo.

/*
 * Fichero: DialogoSecundario.java
 * Autor: Chuidiang
 * Fecha: 1/06/07 23:06
 */
package chuidiang.ejemplos;

import java.awt.Component;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;


/**
 * Ejemplo de como retrasar la creación de un JDialog secundario hasta que se
 * pulse un botón y cómo obtener el padre de este JDialog a partir del ActionEvent.
 *
 * @author Chuidiang
 */
public class DialogoSecundario
{
    /** 
     * JDialog secundario a desplegar. Se inicializa a null para crearlo
     * posteriormente, cuando se pulse el botón.
     */
    JDialog dialogo = null;

    /**
     * Crea un nuevo objeto DialogoSecundario.
     */
    public DialogoSecundario()
    {
    	// Creación de la venana princpial con el botón.
        JFrame v = new JFrame("Prueba Dialogo Secundario");
        JButton b = new JButton("Pulsame");
        v.getContentPane().add(b);
        v.pack();
        v.setVisible(true);
        v.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        // ActionListener del botón.
        b.addActionListener(
            new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                	// Si no está construido ya el JDialog, se construye
                    if (dialogo == null)
                    {
                    	// Obtenemos la ventana que contiene al botón que se ha
                    	// pulsado.
                    	// e.getSource() nos devuelve ese botón.
                    	// SwingUtilities.getWindowAncestor() nos devuelve la ventana
                    	// que contiene ese botón, es decir, en este caso el
                    	// JFrame principal.
                        Window ventanaPadre = SwingUtilities.getWindowAncestor(
                                (Component) e.getSource());

                        // Codigo general para crear el JDialog en función del
                        // tipo de ventana padre.
                        if (ventanaPadre instanceof Frame)
                        {
                            dialogo = new JDialog((Frame) ventanaPadre);
                        }
                        else if (ventanaPadre instanceof Dialog)
                        {
                            dialogo = new JDialog((Dialog) ventanaPadre);
                        }
                        else
                        {
                            dialogo = new JDialog();
                        }

                        // Resto de la construcción del JDialog.
                        dialogo.setTitle("Dialogo Secundario");
                        dialogo.getContentPane().add(new JTextField(20));
                        dialogo.pack();
                    }

                    // Se hace visible el JDialog.
                    dialogo.setVisible(true);
                }
            });
    }

    /**
     * Metodo principal.
     *
     * @param args Se ignora.
     */
    public static void main(String[] args)
    {
        new DialogoSecundario();
    }
}

Una pega es que el constructor de JDialog admite un Frame o un Dialog y no un Window o un Component, por lo que es necesario realizar una serie de if, para en función del tipo de ventana padre, llamar a un constructor u otro. Este trozo de código con los if, si se usa mucho, conviene tenerlo en algún sitio separado. Podría ser una pequeña clase como la siguiente

package chuidiang.ejemplos;

import java.awt.Component;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.Window;

import javax.swing.JDialog;
import javax.swing.SwingUtilities;

public class UtilJDialog {
	public static JDialog dameNuevoJDialog (Component padre)
	{
		JDialog dialogo;
    	// Obtenemos la ventana que contiene al botón que se ha
    	// pulsado.
    	// e.getSource() nos devuelve ese botón.
    	// SwingUtilities.getWindowAncestor() nos devuelve la ventana
    	// que contiene ese botón, es decir, en este caso el
    	// JFrame principal.
        Window ventanaPadre = SwingUtilities.getWindowAncestor(padre);

        // Codigo general para crear el JDialog en función del
        // tipo de ventana padre.
        if (ventanaPadre instanceof Frame)
        {
            dialogo = new JDialog((Frame) ventanaPadre);
        }
        else if (ventanaPadre instanceof Dialog)
        {
            dialogo = new JDialog((Dialog) ventanaPadre);
        }
        else
        {
            dialogo = new JDialog();
        }

        return dialogo;
	}
}

de forma que nos bastaría, en el primer código, con un

dialogo = UtilJDialog.dameNuevoJDialog((Component)e.getSource());