Cómo crear Diálogos

Muchas clases Swing soportan diálogos -- ventanas que son más limitadas que los frames. Para crear un diálogo, simple y estándard se utiliza JOptionPane. Para crear diálogos personalizados, se utiliza directamente la clase JDialog. La clase ProgressMonitor puede poner un diálogo que muestra el progreso de una operación. Otras dos clases, JColorChooser y JFileChooser, también suministran diálogos estándard. Para mostrar un diálogo de impresión se utiliza el método getPrintJob de la clase Toolkit.

El código para diálogos simples puede ser mínimo. Por ejemplo, aquí tenemos un diálogo informativo:

Aquí podemos ver el código que lo crea y lo muestra:
JOptionPane.showMessageDialog(frame, "Eggs aren't supposed to be green.");
El resto de esta página cubre los siguientes tópicos:

Introducción a los diálogos

Todo diálogo depende de un frame. Cuando el frame se destruye, también se destruyen sus diálogos. Cuando el frame es minimizado, sus diálogos dependientes también desaparecen de la pantalla. Cuando el frame es maximizado, sus diálogos dependientes vuelven a la pantalla. El AWT proporciona automáticamente este comportamiento.

Un diálogo puede ser modal. Cuando un diálogo modal es visible, bloquea las entradas del usuario en todas las otras ventanas del programa. Todos los diálogos que proporciona JOptionPane son modales. Para crear un diálogo no modal, debemos utilizar directamente la clase JDialog.

La clase JDialog es una subclase de la clase java.awt.Dialog del AWT. Le añade a Dialog un root pane y soporte para una operación de cerrado por defecto. Estas son las mismas características que tiene JFrame, y utilizar directamente JDialog es muy similar a hacerlo con JFrame. Puedes ver Cómo crear Frames para más información sobre cómo añadir componentes a una ventana y cómo implementar algún oyente de window.

Incluso si utilizamos JOptionPane para implementar un diálogo, estamos utilizando JDialog detrás de la escena. La razón para esto es que JOptionPane es simplemente un contenedor que puede crear automáticamente un JDialog y se añade a sí mismo al panel de contenido de JDialog.

Características de JOptionPane

Utilizando JOptionPane, se pueden crear muchos diálogos. Aquí podemos ver unos ejemplos, todos producidos por DialogDemo.

Como podríamos observar en los ejemplos anteriores, JOptionPane proporciona soporte para mostrar diálogos estándards, proporcionando iconos, específicando el título y el texto del diálogo, y personalizando el texto del botón. Otras características permiten personalizar los componentes del diálogo a mostrar y especificar si el diálogo debería aparecer en la pantalla. Incluso se puede especificar qué panel de opciones se pone a sí mismo dentro de un frame interno (JInternalFrame) en lugar de un JDialog.

Cuando se crea un JOptionPane, el código específico del aspecto y comportamiento añade componentes al JOptionPane y determina la distribución de dichos componentes. La siguiente figura muestra cómo los aspectos y comportamientos más comunes distribuyen un JOptionPane:

icono
(si existe)
mensaje
botones
Para la mayoría de los diálogos modales sencillos, se crea y se muestra el diálogo utilizando uno de los métodos showXxxDialog de JOptionsPane. Para ejemplos de utilización de los siguientes métodos, puedes ver DialogDemo.java. Si nuestro diálogo debería ser un frame interno, se añade Internal después de show -- por ejemplo, showInternalMessageDialog.
showMessageDialog
Muestra un diálogo modal con un botón, etiquetado "OK". Se puede especificar fácilmente el mensaje, el icono y el título que mostrará el diálogo.
showConfirmDialog
Muestra un diálogo modal con dos botones, etiquetados "Yes" y "No". Estas etiquetas no son siempre terriblemente descriptivas con las actiones específicas del programa que causan.
showInputDialog
Muestra un diálogo modal que obtiene una cadena del usuario. Un diálogo de entrada muestra un campo de texto para que el usuario teclee en él, o un ComboBox no editable, desde el que el usuario puede elegir una de entre varias cadenas.
showOptionDialog
Muestra un diálogo modal con los botones, los iconos, el mensaje y el título especificado, etc. Con este método, podemos cambiar el texto que aparece en los botones de los diálogos estándard. También podemos realizar cualquier tipo de personalización.

El soporte de iconos de JOptionPane permite especificar qué icono mostrará el diálogo. Podemos utilizar un icono personalizado, no utilizar ninguno, o utilizar uno de los cuatro iconos estándard de JOptionPane (question, information, warning, y error). Cada aspecto y comportamiento tiene sus propias versiones de los cuatro iconos estándard. La siguiente imagen muestra los iconos utilizados en el Aspecto y Comportamiento Java (popularmente conocido como Metal).

Iconos proporcionados por JOptionPane
(Aspecto y Comportamiento Java)
question information warning error

Por defecto, un diálogo creado con showMessageDialog muestra el icono de información, un diálogo creado con showConfirmDialog o showInputDialog muestra un icono question. Para especificar qué un diálogo estándard no tenga icono o tenga otro icono estándard, se añade un parámetro que especifica el tipo de mensaje. El valor del tipo de mensaje puede ser una de las siguientes constantes: PLAIN_MESSAGE (sin icono), QUESTION_MESSAGE, INFORMATION_MESSAGE, WARNING_MESSAGE, o ERROR_MESSAGE. Si especificamos un objeto Icon distinto de null, el diálogo muestra ese icono, no importa el tipo de mensaje que sea. Aquí tenemos un ejemplo que crea un díalogo sencillo que muestra un mensaje de error

JOptionPane.showMessageDialog(frame,
                              "Eggs aren't supposed to be green.",
                              "Inane error",
                              JOptionPane.ERROR_MESSAGE);
Normalmente, el área del mensaje de un panel de opciones tiene una sóla línea de texto, como "Eggs aren't supposed to be green." Podemos dividir el mensaje en varias líneas poniendo caracteres de nueva línea (\n) dentro del string del mensaje. Por ejemplo:
"Complete the sentence:\n"
+ "\"Green eggs and...\""
Podemos especificar el texto mostrado por los botones del panel. Un ejemplo de esto está en Personalizar el texto de los botones en un diálogo estándard. Cuando el usuario pulsa cualquier botón, el diálogo desaparece automáticamente. si no queremos que el diálogo desaparezca automáticamente -- por ejemplo, si queremos asegurarnos de que la entrada del usuario es válida antes de cerrar el diálogo -- necesitamos seguir los pasos descritos en Detener la salida Automática de un Diálogo.

Cuando se llama a uno de los métodos showXxxDialog de jOptionPane, el primer argumento especifica un componente. Este componente determina la posición en la pantalla del díalogo y del frame del que éste depende. Si especificamos null para el componente, el diálogo es independiente de cualquier frame visible, y aparece en el medio de la pantalla. La siguiente figura muestra lo que sucede cuando se indica un JFrame como primer argumento.

a dialog centered over a window

El Ejemplo DialogDemo

Aquí tenemos una imagen de una aplicación que muestra diálogos.

Intenta esto:
  1. Compila y ejecuta la aplicación, El fichero fuente es DialogDemo.java.
  2. Pulsa el botón "Show it!".
    Aparecerá un diálogo modal. Hasta que lo cierres, la aplicación no responderá, aunque se redibujará a sí misma si es necesario. Puedes salir del diálogo pulsando un botón o explícitamente utilizando el icono de cerrado de la ventana.
  3. Minimiza la ventana DialogDemo mientras se muestra el diálogo.
    El diálogo desaparecerá de la pantalla hasta que maximices la ventana de DialogDemo.
  4. En el panel "More Dialogs", pulsa el botón de rádio iferior y luego el botón "Show it!". Aparecerá un diálogo no modal. Observa que la ventana de DialogDemo permanece totalmente funcional mientras está activo el diálogo no modal.

Personalizar el texto de los botones en un diálogo estándard

Cuando se utiliza JOptionPane para crear un diálogo estándard, podemos elegir si utilizar el texto estándard del botón (que podría variar dependiendo del aspecto y comportamiento) o especificar un texto diferente..

El siguiente código, tomado de DialogDemo.java, crea dos diálogos Yes/No. El primer diálogo utiliza las palabras del aspecto y comportamiento para los dos botones. El segundo diálogo personaliza las palabras. Con la excepción del cambio de palabras, los diálogos son idénticos. Para personalizar las palabras, el código que crea el segundo diálogo utiliza showOptionDialog, en vez de showConfirmDialog.

A yes/no dialog
...//create the yes/no dialog:
int n = JOptionPane.showConfirmDialog(
	frame, "Would you like green eggs and ham?",
	"An Inane Question",
	JOptionPane.YES_NO_OPTION);
if (n == JOptionPane.YES_OPTION) {
    setLabel("Ewww!");
} else if (n == JOptionPane.NO_OPTION) {
    setLabel("Me neither!");
} else {
    setLabel("Come on -- tell me!");
}
A yes/no dialog -- in other words
...//create the yes/no (but in other words) dialog:
String string1 = "Yes, please";
String string2 = "No way!";
Object[] options = {string1, string2};
int n = JOptionPane.showOptionDialog(frame,
		"Would you like green eggs and ham?",
		"A Silly Question",
		JOptionPane.YES_NO_OPTION,
		JOptionPane.QUESTION_MESSAGE,
		null,     //don't use a custom Icon
		options,  //the titles of buttons
		string1); //the title of the default button
if (n == JOptionPane.YES_OPTION) {
    setLabel("You're kidding!");
} else if (n == JOptionPane.NO_OPTION) {
    setLabel("I don't like them, either.");
} else {
    setLabel("Come on -- 'fess up!");
}

Obtener entrada del usuario desde un diálogo

Cómo se vió en el ejemplo anterior, los métodos showXxxDialog de JOptionPane devuelven un valor que indica la elección del usuario. Si, por otro lado, estamos diseñando un diálogo personalizado, necesitamos diseñar el API de nuestro diálogo para que pueda preguntar al usuario sobre la elección del usuario.

Para los diálogos estándard JOptionPane, los métodos showXxxDialog devuelven un entero. Los valores por defecto para este entero son YES_OPTION, NO_OPTION, CANCEL_OPTION, OK_OPTION, y CLOSED_OPTION. Excepto para CLOSED_OPTION, cada opción correponde con el botón pulsado por el usuario. Cuando se devuelve CLOSED_OPTION, indica que el usuario ha cerrado la ventana del diálogo explícitamente, en vez de elegir un botón.

Incluso si cambiamos los textos de los botones del diálogo estándard (como en el ejemplo anterior), el valor devuelto sigue siendo uno de los enteros predefinidos. Por ejemplo, un diálogo YES_NO_OPTION siempre devuelve uno e los siguientes valores: YES_OPTION, NO_OPTION, o CLOSED_OPTION.

Detener la Despedida Automática de un Diálogo

Por defecto, cuando el usuario crea un botón del JOptionPane o cierra su ventana explícitamente, el diálogo desaparece. Pero ¿que pasa si queremos comprobar la respuesta del usuario antes de cerrar la ventana? En este caso, debemos implementar nuestro propio oyente de change para que cuando el usuario pulse un botón, el diálogo no desparezca automáticamente.

DialogDemo contiene dos diálogos que implementan un oyente de change. Uno de esos diálogos es un diálogo modal, implementado en CustomDialog.java, que utiliza JOptionPane para obtener los iconos estándard y para obtener asistencia en la distribución. El otro diálogo, cuyo código está abajo, utiliza un JOptionPane estándard Yes/No. Aunque este diálogo es poco más que inútil, su código es lo suficientemente sencillo como para poder utilizarlo como plantilla para diálogos más complejos.

Junto con la configuración del oyente de change, el código siguiente también llama al método setDefaultCloseOperation de JDialog e implementa un oyente de window que maneja apropiadamente el intento de cierre de la ventana. Si no nos importa ser notificados cuando el usuario cierre la ventana explícitamente, podemos ignorar el código que no está en negrita.


final JOptionPane optionPane = new JOptionPane(
		"The only way to close this dialog is by\n"
		+ "pressing one of the following buttons.\n"
		+ "Do you understand?",
		JOptionPane.QUESTION_MESSAGE,
		JOptionPane.YES_NO_OPTION);

final JDialog dialog = new JDialog(frame, 
			     "Click a button",
			     true);
dialog.setContentPane(optionPane);
dialog.setDefaultCloseOperation(
    JDialog.DO_NOTHING_ON_CLOSE);
dialog.addWindowListener(new WindowAdapter() {
    public void windowClosing(WindowEvent we) {
	setLabel("Thwarted user attempt to close window.");
    }
});
optionPane.addPropertyChangeListener(
    new PropertyChangeListener() {
	public void propertyChange(PropertyChangeEvent e) {
	    String prop = e.getPropertyName();

	    if (dialog.isVisible() 
	     && (e.getSource() == optionPane)
	     && (prop.equals(JOptionPane.VALUE_PROPERTY) ||
		 prop.equals(JOptionPane.INPUT_VALUE_PROPERTY))) {
		//If you were going to check something
		//before closing the window, you'd do
		//it here.
		dialog.setVisible(false);
	    }
	}
    });
dialog.pack();
dialog.show();

int value = ((Integer)optionPane.getValue()).intValue();
if (value == JOptionPane.YES_OPTION) {
    setLabel("Good.");
} else if (value == JOptionPane.NO_OPTION) {
    setLabel("Try using the window decorations "
	     + "to close the non-auto-closing dialog. "
	     + "You can't!");
}

El API Dialog

Las siguiente tablas listan los métodos y constructores más utilizados de JOptionPane y JDialog. Otros métodos que podríamos utilizar están definidos por las clases JComponent y Component.

El API se lista de esta forma:

Mostrar diálogos modales estándard (utiizando métodos de la clase JOptionPane)
Método Propósito
int showMessageDialog(Component, Object)
int showMessageDialog(Component, Object, String, int)
int showMessageDialog(Component, Object, String, int, Icon)
Muestra un diálogo modal con un botón.
int showOptionDialog(Component, Object, String, int, int, Icon, Object[], Object) Muestra un diálogo.
int showConfirmDialog(Component, Object)
int showConfirmDialog(Component, Object, String, int)
int showConfirmDialog(Component, Object, String, int, int)
int showConfirmDialog(Component, Object, String, int, int, Icon)
Muestra un diálogo modal que [PENDIENTE: elaborar].
String showInputDialog(Object)
String showInputDialog(Component, Object)
String showInputDialog(Component, Object, String, int)
String showInputDialog(Component, Object, String, int, Icon, Object[], Object)
Muestra un diálogo de entrada.
int showInternalMessageDialog(...)
int showInternalOptionDialog(...)
int showInternalConfirmDialog(...)
String showInternalInputDialog(...)
Implementa un diálogo estándard como un frame interno.

Métodos para utilizar JOptionPane directamente
Método Propósito
JOptionPane()
JOptionPane(Object)
JOptionPane(Object, int)
JOptionPane(Object, int, int)
JOptionPane(Object, int, int, Icon)
JOptionPane(Object, int, int, Icon, Object[])
JOptionPane(Object, int, int, Icon, Object[], Object)
Crea un ejemplar de JOptionPane.
Frame getFrameForComponent(Component)
JDesktopPane getDesktopPaneForComponent(Component)
Manejan métodos de clase de JOptionPane que encuentran el frame o desktop pane, respectivamente, en el que se encuentra el componente especificado.

Otros Constructores y Métodos de JOptionPane
Métodos Propósito
JOptionPane()
JOptionPane(Object)
JOptionPane(Object, int)
JOptionPane(Object, int, int)
JOptionPane(Object, int, int, Icon)
JOptionPane(Object, int, int, Icon, Object[])
JOptionPane(Object, int, int, Icon, Object[], Object)
Crea un ejemplar de JOptionPane.

Constructores y Métodos más utilizados de JDialog
Método Propósito
JDialog()
JDialog(Frame)
JDialog(Frame, boolean)
JDialog(Frame, String)
JDialog(Frame, String, boolean)
Crea un ejemplar de JDialog. El argumento Frame, si existe, es el frame (normalmente un objeto JFrame) del que depende el diálogo. Se hace el argumento booleano true para especificar un diálogo modal, false o ausente, para especificar un diálogo no modal. También se puede especificar el título de un diálogo utilizando un argumento string.
Container getContentPane()
setContentPane(Container)
Obtiene y selecciona el panel de contenido que normalmente es el contenedor de todos los componentes del diálogo.
int getDefaultCloseOperation()
setDefaultCloseOperation(int)
Obtiene y selecciona lo que sucece cuando el usuario intenta cerrar el diálogo. Valores posibles: DISPOSE_ON_CLOSE, DO_NOTHING_ON_CLOSE, HIDE_ON_CLOSE (por defecto).
void setLocationRelativeTo(Component) Centra el diálogo sobre el componente especificado.

Ejemplos que utilizan Diálogos

Esta tabla lista ejemplos que utilizan diálogos y dónde se describen.

Ejemplo Dónde se Describe Notas
DialogDemo.java,
CustomDialog.java
Esta página Crea muchas clases de diálogos utilizando JOptionPane y JDialog.
Framework.java Todavía no. Trae un diálogo de confirmación cuando el usuario selecciona el ítem de menú Quit.
ListDialog.java Cómo usar BoxLayout Implementa un diálogo modal que contiene una lista desplazable y dos botones.
PasswordDemo.java Cómo usar Threads Utiliza un diálogo para pedir una password al usuario.
TableDemo.java Cómo usar Tablas Muestra un diálogo de aviso cuando el usuario introduce una entrada no numérica en una celda que debe contener un número.


Ozito