sábado, 24 de julio de 2010

Dialogos Modales y No Modales en Java SE 6. Novedades Swing.

Saludos compañeros nos vemos otra vez aquí, para compartir ideas y experiencias de Java. Esta vez le toca el turno a los diálogos modales, mostraremos que conforma el nuevo API de Java SE 6 para crear diálogos modales y evitar diálogos modales, empecemos:

En versiones anteriores de Java ya existía una forma de crear diálogos modales a través del parámetro boolean (modal o no) del constructor de la clase java.awt.Dialog, este parámetro al ser verdadero (true) bloqueaba toda la aplicación y hasta que ella se cerrara no se podía seguir con la aplicación. Veamos un pequeño en ejemplo con este constructor:



package mipaquete;
import javax.swing.*;

public class Marco {
   public static void main(String[] args) {
      JFrame f = new JFrame("");
      f.setAlwaysOnTop(true);
      f.setSize(300,300);
      f.setVisible(true);
      JDialog d = new JDialog(f, "Dialog", true);
      d.setSize(300,300);
      d.setLocationRelativeTo(null);
      d.setVisible(true);
   }
}


Si se ejecuta este párrafo anterior se muestra un Frame y un Diálogo, hasta que no sea cerrado el diálogo no puede tomar el foco el Frame, es decir no tengo acceso a él.

Si tengo una aplicación en la cual deseo que no toda la aplicación sea bloqueada sino sólo parte de ella, puedo hacer uso del nuevo API de Java 6 donde se incluyen dos clases estáticas dentro de la clase Dialog, estas son:


static class ModalityType y static class ModalExclusionType, ambas tienen dentro de sí una enumeracion que indican el nivel de bloqueo que pueden generar.

static class ModalityType, esta clase sirve para definir el tipo de bloqueo, o también llamado alcance del bloqueo en una aplicación, su enumeración contiene:

APPLICATION_MODAL: Bloquea todas las ventanas de la aplicación, excepto las ventanas que se deriven de ella, es decir, las ventanas que estén abiertas para el momento en que se muestra este diálogo quedan bloqueadas, pero si a partir de ese momento se crean nuevas ventanas (ventanas hijas) estas no serán bloqueadas.

DOCUMENT_MODAL: Bloquea la ventana padre de la ventana y su jerarquía superior, es decir bloque las ventanas de donde fue derivada, pero esto no incluyen las ventanas que no pertenecen a esta jerarquía por lo tanto algunas ventanas quedarán sin bloquear.

MODELESS: no bloquea ninguna ventana.

TOOLKIT_MODAL: Bloquea las ventanas de nivel superior que corren en el mismo TOOLKIT.

Podemos excluir del bloqueo a una ventana o diálogo utilizando la clase ModalExclusionType, esta puede excluir del bloqueo según alguna de estas opciones de su enumeración:

APPLICATION_EXCLUDE: La ventana que utiliza este valor de enumeracion no será bloqueada por ningún diálogo de la aplicación.

NO_EXCLUDE: Indica que la ventana no estará excluida del bloqueo si este ocurriera.

TOOLKIT_EXCLUDE: Indica que no se bloqueará esta ventana si se llamase a APPLICATION_MODAL o TOOLKIT_MODAL.

Lo que nos faltaría por ver son los métodos agregados en Java SE 6.0 que nos permiten utilizar estas enumeraciones:

En la clase java.awt.Dialog se incluyeron los métodos setModalityType() que recibe un Dialog.ModalityType para definir el alcance del bloqueo, también se agregó el método getModalityType(), entre otros.

En la clase Windows se incluyó el método setModalExclusionType() que recibe un elemento de la enumeracion ModalExclusionType para definir que tipo de exclusión será aplicada, también se cuenta con el método getModalExclusionType(), el uso es obvio.

También se agregaron los constructores public Dialog(Window owner, String title,Dialog.ModalityType modalityType) y public Dialog(Window owner, String title, Dialog.ModalityType modalityType, GraphicsConfiguration gc), GraphicsConfiguration queda fuera del alcance de este artículo.

Ahora si estamos listos para crear nuestra aplicación con Ventanas y Diálogos modales con las nuevas modalidades Java SE 6.0. Veamos:


package modality;
import java.awt.*;
import java.awt.Dialog.*;
import java.awt.event.*;
import javax.swing.*;

public class ClaseModal {

static JFrame padre;

public static void main(String[] args) {
      padre = new JFrame("Marco1");
      padre.setLayout(new BorderLayout());
      JButton btnNuevaVentana =
        new JButton("Boton Mostrar Hija");
      JLabel etiqueta = new JLabel("Etiqueta");
      etiqueta.setBackground(Color.BLUE);
      padre.add(etiqueta, BorderLayout.CENTER);
      padre.add(btnNuevaVentana, BorderLayout.SOUTH);
      btnNuevaVentana.addActionListener(
        new ActionListener(){
         @Override
         public void actionPerformed(ActionEvent e) {
              JDialog dialogoAuxiliar =
                  new JDialog(padre, "hija",
                    Dialog.ModalityType.DOCUMENT_MODAL);
                  JButton btnSaveAs =
                    new JButton("Save as...");
                  btnSaveAs.addActionListener(
                    new ActionListener(){
                  @Override
             public void actionPerformed(ActionEvent e) {
//Disminucion de sanguia por cuestiones de espacio
               FileDialog fileDialog =
                 new FileDialog(padre,
               "Guardar", FileDialog.SAVE);
               fileDialog.setSize(400,400);
               fileDialog.setVisible(true);
                  }
                  });
                  dialogoAuxiliar.add(btnSaveAs);
                  dialogoAuxiliar.setSize(300,300);
                  dialogoAuxiliar.setLocation(150,150);
                  dialogoAuxiliar.setVisible(true);
   }
});
padre.setSize(300,300);
padre.setVisible(true);
JFrame ventanaIndependiente =
new JFrame("Ventana Independiente");
ventanaIndependiente.setModalExclusionType(
Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
ventanaIndependiente.setSize(500,500);
ventanaIndependiente.setLocation(75, 75);
ventanaIndependiente.setVisible(true);
}
}


Al ejecutar esta aplicación se obtienen 2 ventanas, una ventana Padre y una Independiente. Al hacer click en el botón Mostrar Hija, se desplega una ventana hija que bloquea la padre (DOCUMENT_MODAL), la ventana hija tiene un único botón que llama un FileDialog (Cuadro de dialogo Guardar), este Cuadro de diálogo tampoco bloquea la ventana independiente ya que utiliza a Dialog.ModalExclusionType.APPLICATION_EXCLUDE, si se utilizara Dialog.ModalExclusionType.NO_EXCLUDE o simplemente no se asigna ningún ModalExclusionType, entonces la ventana independiente se bloquearía con el cuadro de diálogo SAVE.

Bueno, espero haberme explicado y este código les ayude a resolver dudas o inquietudes que se les hayan podido encontrar, cualquier pregunta tenemos los comentarios abiertos, para ampliar el tema, o resolver dudas, por mi parte me despido hasta una próxima edición.

12 comentarios:

Héctor Tobón dijo...

Me encanta tu blog.
Soy Ing. de Sistemas y lo leo con cada actualización que haces.

Un día de estos te referiré desde mi blog personal.

Saludos.

NOTA: Este tema de los diálogos modales, me interesaría conocerlo con más detalle adaptado a las ventanas (JFrame). Es decir, Si la aplicación ya dispone de una ventana principal y se abren nuevas ventanas (tal vez alguna ventana para configurar la aplicación), que la ventana principal se bloquee hasta que las demás ventanas se cierren.

Gracias!

Kelvin dijo...

Saludos Héctor, gracias por tus comentarios.

Por una parte gracias por tu confianza depositada hacia este blog, estoy complacido de que te sea de ayuda y te haga aportes. Estamos para servir y compartir información. Espero que te sirva tanto para crecimiento personal como profesional. Este trabajo vale la pena si existen personas interesadas en la información.

Tocando sobre la pregunta que planteas, es necesario mencionar que las ventanas JFrame no pueden ser modales, sólo los JDialog, por lo tanto te recomiento que cambies sólo el constructor de JFrame de configuración a JDialog y lo asignes Modal con el método setModal(true) de JDialog antes de desplegarla.

Espero haberme explicado, para ver las diferencias entre JFrame y Dialog visita el enlace. Si continua la duda, sigue escribiendo. COn gusto seguiría la expicación.

Unknown dijo...

zo0247050

Unknown dijo...

Excelente blog directo y al grano,

Anónimo dijo...

Exelente tema puesto que me a ayudado en un trabajo, de ahora en adelante seguire mas de cerca tus publicasiones.
Muy buena explicacion.

Anónimo dijo...

Como hago para pasarle al (constructor?) de un jdialog un padre jframe? ayuda.

Kelvin dijo...

Saludos Anónimo:

Para pasarle al constructor de JDialog un JFrame se hace lo siguiente:

Se crea la instancia de JFrame:

JFrame marco = new JFrame("Titulo del Marco");

Luego se pasa al constructor de JDialog:

JDialog dialogo = new JDialog(marco, "Titulo del JDialog");

Espero te haberte resuelto la duda, si tienes otra o quieres otros detalles puedes seguir escribiendo.

Anónimo dijo...

Muchas gracias estimado kelvin por responder.. Buen aporte muchacho!
En realidad dudas son las q me sobran con esto de java :), pero en su mayoria son dudas teóricas pienso, debido al tiempo q tengo apenas. Recien comienzo y estoy indagando cada dia acerca de este lenguaje tan interesante. Realizo una aplicacion y consegui lo q buscaba, cambiar el icono java de las ventanas. Pero ahora en un boton donde mando a imprimir un jTable (exactamente en la tabla de propiedades de impresion) no e podido cambiar dicho icono. Como hago alli?

Néstor dijo...

Buenas, te remito un problema que estoy teniendo con los diálogos modales.

Tengo un componente que hereda de jtextfield al cual le he implementado un jmenu con la función copy, cut & paste...

Funciona perfectamente al no ser que el diálogo sea modal... En dicho caso se muestra el menú y desaparece al hacer click sobre el mismo pero no ejecuta la acción asociada...

¿Qué crees que pueda ser? El menu se dispara desde un componente del diálogo modal, no debería ser bloqueado ya que por defecto los diálogos son de tipo aplicación-modal.

PD. Uso Java 6 SE.

Un saludo!

pablo dijo...

Por fin encontré lo que buscaba, no sabía como hacer que el dialogo bloqueara la ventana principal. Muchas gracias

Anónimo dijo...

buen dia, me base en la info de este blog, pero tengo un pequeño problema:

Tengo un JFrame, y desde un boton llamo un JDialog, pero pasa lo siguiente
si el Jdialog, lo hago modal, sus componentes no les funciona los listener.
si lo dejo como no modal, los listener funcionan perfecto.

Sabes a que se deba?
De antemano, gracias

Anónimo dijo...

Hola,

Estoy aprendiendo java y he descubierto su blog. Tengo una duda, me gustaría saber que significa que las ventanas corran bajo el mismo toolkit.

Muchas gracias por todo,
Un saludo,
Laura.