¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Desarrollo informático
  3. JTable
Extrait - Desarrollo informático Aprenda a diseñar antes de programar
Extractos del libro
Desarrollo informático Aprenda a diseñar antes de programar Volver a la página de compra del libro

JTable - DAO - MVC

Objetivos del capítulo

  • Aprender a utilizar el componente gráfico JTable.

  • Diseñar clases de herramientas para facilitar la utilización de una JTable.

  • Diseñar una aplicación respetando el modelo MVC (Modelo - Vista - Controlador).

  • Diseñar una capa de acceso a los datos de la aplicación (Data Access Object).

Funcionamiento por defecto de una JTable

1. Ventana mostrada

images/1_213.png

2. Clase Ventana: utilización de una JTable

a. Clase Ventana

La ventana contiene tres componentes: el panel de fondo, una JTable y un JScrollPane cuyo cliente es la JTable:

public class Ventana extends JFrame  
{  
   private JPanel panelDeFondo;  
   private JTable tablas;  
   private JScrollPane scroll; 

El constructor de la ventana recibe la lista de filas y columnas que hay que mostrar:

   public Ventana(String s, Vector<Vector<Object>> listaFilas, 
                             Vector<String> listaColumnas)  
   {  
       super(s);  
       addWindowListener(new EscuchaVentana());  
  
       panelDeFondo = new JPanel(); 

El panel de fondo se organiza en BorderLayout:

       panelDeFondo.setLayout(new BorderLayout());  
       panelDeFondo.setPreferredSize(new Dimension(500, 150)); 

Para la instanciación de la JTable, se envía como argumentos la lista de filas y columnas que se han de mostrar (el constructor utilizado aquí recibe los Vector como argumentos): 

       tablas = new JTable(listaFilas, listaColumnas); 

La siguiente instrucción permite evitar el cambio automático de tamaño de las columnas cuando la ventana se redimensiona. Sin esta instrucción, el desplazamiento horizontal no aparece.

       tablas.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);  
  
       scroll = new JScrollPane(tabla);  
       scroll.getViewport().setBackground(Color.pink);  
  
       panelDeFondo.add(scroll);  
  
       getContentPane().add(panelDeFondo);  
       pack();  
       setVisible(true);  
   }  
} 

El JScrollPane se añade al panel de fondo....

Modelo de tablas

La construcción de una JTable a partir de dos vectores es sencilla, pero el comportamiento de la JTable es rudimentario. Otros constructores de JTable utilizan los modelos de tablas.

1. Definición

Un modelo de tablas es una clase que implementa la interfaz TableModel. Esta interfaz contiene métodos que permiten definir el comportamiento de la JTable.

2. Clases e interfaces para crear un modelo de tablas

images/4_213.png

La interfaz TableModel declara todos los métodos que se deben sobrecargar para escribir un modelo de tabla.

La clase AbstractTableModel sobrecarga todos los métodos, salvo tres. Estos métodos son:

  • getRowCount(): devuelve el número de filas de la tabla.

  • getColumnCount(): devuelve el número de columnas de la tabla.

  • getValueAt(int fila, int columna): devuelve el valor que se muestra en la celda de la tabla, indicada por los argumentos fila y columna.

La clase DefaultTableModel es la que hemos utilizado sin saberlo en la JTable, en la sección Funcionamiento por defecto de una JTable. Utiliza un Vector de Vectores para almacenar los valores de las celdas.

Para crear un modelo de tablas personalizado (ModeloTabla por ejemplo), es suficiente consobrecargar estos tres métodos. No hay nada que impida sobrecargar el resto.

3. Modelo de tablas - Clase Columna

a. Ventana mostrada

El objetivo es poner a punto una aplicación que presente esta visualización:

images/5_213.png

b. Clase Columna (package herramientasMG.varios)

La clase Columna del paquete herramientasMG.varios define tres propiedades:

  • nombre: nombre de la columna,

  • longitud: número de caracteres máximo de los datos de la columna,

  • tipo: tipo de datos mostrados en la columna (ejemplo: java.lang.String). 

La clase Columna permite almacenar tres datos que son útiles para definir el comportamiento de la JTable. La longitud permite ajustar la dimensión de cada columna. El tipo permite adaptar la paginación. Estos dos datos sirven también para realizar controles sobre el valor introducido.

package herramientasMG.varios;  
  
public class Columna implements java.io.Serializable  
{  
   private String nombre;  
   private Integer longitud;  
   private String tipo;  
  
   public Columna()  
   {  
   }  ...

Modelo de columnas

El comportamiento de una JTable se puede afinar todavía más, usando un modelo de columnas. Constructores de JTable utilizan modelos de tablas Y modelos de columnas.

1. Definición

Un modelo de columnas de tablas es una clase que implementa la interfaz TableColumnModel

2. Clases e interfaces para crear un modelo de columnas

images/11_213.png
  • La interfaz TableColumnModel declara todos los métodos que se deben sobrecargar para escribir un modelo de columnas de tablas.

  • La clase DefaultTableColumnModel sobrecarga todos los métodos de la interfaz. Por lo tanto, es directamente utilizable.

  • La clase TableColumn permite definir toda la información relativa a UNA columna. 

Para crear un modelo de tablas personalizado, podemos heredarDefaultTableColumnModel y añadir tantos objetos TableColumn como columnas muestre la JTable.

3. Modelo de tablas y modelo de columnas

a. Ventana mostrada

La pantalla que se debe mostrar sigue siendo la misma:

images/12_213.png

Sin embargo, observe que la anchura de las columnas se adapta a su contenido.

b. Clase ModeloColumnaTabla

La clase ModeloColumnaTabla hereda de DefaultColumnModel:

public class ModeloColumnaTabla extends DefaultTableColumnModel  
{ 
  • tamanioCaracter: es el número de puntos máximo ocupado por cada carácter. Por defecto, este número se fija a 10, pero uno de los constructores recibe un tamaño como argumento.

  • numeroCaracteresMin, numeroCaracteresMax: número de caracteres mínimo y máximo de una columna. Estos dos argumentos se pueden modificar con los métodos setNumeroCaracteresMin() y setNumeroCaracteresMax().

  • listaColumnas: Vector<Columna> que contiene la información de las columnas. 

   private int tamanioCaracter = 10;  
   private int numeroCaracteresMin = 8;  
   private int numeroCaracteresMax = 20;  
   private Vector<Columna> listaColumnas; 

Los dos constructores llaman al método crearColumnas(). El primer constructor recibe el número de puntos ocupado por un carácter:

   public ModeloColumnaTabla(Vector<Columna> listaColumnas,  
                             ...

JTable editable

1. Ventana mostrada

La JTable es editable. Tiene una fila adicional para añadir un contacto, como se muestra en la siguiente pantalla:

images/13_213.png

2. Diseño de las clases ModeloTabla y ModeloTablaContacto

a. Métodos añadidos a la clase ModeloTablaContacto

  • Para que una celda de la JTable sea editable, el método isCellEditable() de la clase AbstractTableModel se debe sobrecargar. Este método devuelve un boolean que vale true si la celda de la fila fila y de la columna col es editable, y false en caso contrario.

   public boolean isCellEditable(int fila, int col)  
   {  
       return true;  
   } 

Sobrecargada de esta manera, todas las celdas de la JTable son editables.

  • El método getRowCount() de la clase ModeloTabla se debe sobrecargar en la clase ModeloTablaContacto para devolver una fila adicional destinada a la inserción:

   public int getRowCount()  
   {  
       return super.getRowCount() + 1;  
   } 

Por defecto, una JTable es no editable. La clase ModeloTabla respeta esta opción. Es responsabilidad de las clases heredadas modificar esta opción si el diseñador lo desea. Por lo tanto, las sobrecargas de los métodos isCellEditable() y getRowCount() se sitúan en ModeloTablaContacto.

b. Métodos añadidos o modificados en ModeloTabla

El método getValueAt() debe devolver valores para las celdas de la fila adicional. Por lo tanto, hay que redefinirla. Devuelve null para las celdas de la fila vacía adicional:

   public Object getValueAt(int...

El paquete de herramientasMG.grafico.tabla

Las clases ModeloTabla y ModeloColumnaTabla del paquete herramientasMG.grafico.tabla se enriquecen con numerosos métodos.

1. ModeloTabla

La clase ModeloTabla prevé todas las operaciones de actualización del vector de las filas en caso de modificaciones realizadas en la JTable (adición, eliminación o modificación de filas). Se han añadido los siguientes métodos:

  • public int eliminar(int[] filasSeleccionadas) permite eliminar filas del vector de filas listaFilas. Los números de estas filas están contenidos en la tabla filasSeleccionadas.

  • public void restaurar() permite restaurar las filas eliminadas.

  • public Vector<Vector<Object>> getListaFilasEliminadas() permite obtener la lista de filas eliminadas.

  • public Vector<Caracter> getMarcadoresFilas() permite obtener una lista de caracteres correspondiente a cada fila del vector listaFilas.

  • Este carácter vale ‘M’ si la fila correspondiente se ha modificado.

  • Este carácter vale ‘I’ si la fila correspondiente se ha insertado.

  • Este carácter vale ‘ ’ (blanco) si la fila correspondiente no se ha modificado.

2. ModeloColumnaTabla

La clase ModeloColumnaTabla usada en los ejemplos de este capítulo utiliza las opciones de edición y visualización por defecto de una JTable.

Pero algunas veces, estas opciones son «extrañas»....

Capa de acceso a datos - DAO (Data Access Object)

1. Aplicación JTable editable (párrafo 5)

El diagrama de secuencia de esta aplicación es:

images/18_213.png

El método main() llama a los métodos crearListaContactos() y crearListaColumnas() y crea la Ventana que se muestra.

2. La capa de acceso a datos: la DAO

En el ejemplo anterior, la clase principal (Controlador) crea la lista con los objetos Contacto y la lista con los objetos Columna. Si se inicializan estos objetos a partir de datos que provienen de una fuente de datos (SGBD, red, etc.), hay que modificar considerablemente la clase principal.

Es preferible delegar la creación de estas listas a otra clase. Este es el objetivo de la capa de acceso a datos.

La clase ContactoDAO se encarga de formar los dos vectores necesarios para la visualización de la tabla de los contactos. El diagrama se convierte en:

images/19_213.png
  • Las flechas completas son llamadas a métodos.

  • Las flechas punteadas son los valores de retorno de los métodos.

El código se obtiene por medio de la creación de una nueva clase (ContactoDAO) y por acertados copiar/pegar. Pero terminamos nuestro diseño respetando una segunda restricción: el modelo MVC.

Modelo MVC (Modelo - Vista - Controlador)

1. Definición

El modelo MVC reparte las clases de la aplicación en tres categorías:

  • La Vista (View): es lo que ve el usuario de la aplicación, la interfaz visual con la que se comunica.

  • El Modelo (Model): las clases del modelo contienen la lógica de tratamiento de los datos de la aplicación. Los accesos a los diferentes orígenes de datos (bases de datos, workflows de datos, etc.), se hacen en esta parte de la aplicación.

  • El Controlador (Controller): es la parte de la aplicación que sirve como intermediario entre la Vista y el Modelo.

En el modelo MVC, los objetos de la vista no tienen contacto con los del modelo. Podemos decir que los objetos de la Vista y del Modelo no se conocen. Sus relaciones pasan obligatoriamente por el Controlador.

El siguiente esquema ilustra las relaciones entre clases en el modelo MVC:

images/20_213.png

2. Aplicación «JTable editable», versión final

a. La aplicación «JTable editable» respeta el MVC

La clase Ventana es la Vista.

La clase ContactoDAO fabrica los datos de la aplicación. Es el Modelo.

La clase Controlador se dirige al Modelo y a la Ventana. Es el Controlador.

El diagrama de secuencia lo muestra claramente. Nuestra aplicación respeta el MVC. Todas las comunicaciones entre la vista y el modelo pasan por el controlador.

Ninguna flecha atraviesa el controlador.

b. Parada de la aplicación

El observador de eventos WindowEvent de la Ventana es la clase EscuchaVentana del paquete herramientasMG.grafico:

   public Ventana(String s, Vector<Contacto> listaContactos,  
                           Vector<Columna> listaColumnas)  
   {  
       super(s);  
       addWindowListener(new EscuchaVentana());  
       . . . 

La clase EscuchaVentana sobrecarga el método windowClosing():

public class EscuchaVentana extends WindowAdapter  
{  
   public void windowClosing(WindowEvent e)  
   {  
       System.exit(0);  
   }  
} 

Cuando el usuario cierra la ventana, la aplicación se detiene bruscamente: es la Vista la que detiene...

Trabajo práctico: Proyecto GestionContactoLocal

1. Objetivo

Mejorar la interfaz gráfica de la aplicación «JTable editable»:

  • Modificar la clase Ventana y adaptar la clase Controlador a las nuevas funcionalidades.

  • Respetar la arquitectura MVC.

2. Tema

a. Funcionamiento de la aplicación

Escribir una aplicación que permita mostrar la siguiente pantalla:

images/24_213.png

Cuando se elige Pago o Sector: mostrar un cuadro de diálogo (ventana modal):

images/25_213.png

Cuando se pulse en Contacto: mostrar una ventana interna que contenga la lista de los contactos:

images/26_213.png
  • Es posible añadir y modificar los contactos.

  • La ventana interna CONTACTOS tiene un menú que permite eliminar y restaurar las filas de la tabla.

  • Cuando la ventana interna CONTACTOS se cierra, las modificaciones se muestran en la consola.

Ejemplo

images/27_213.png

b. Diseño

A partir del diagrama de secuencia de «JTable editable», escribir el diagrama de secuencia de la aplicación GestionContactoLocal.

c. Programación

Las clases Contacto, ContactoDAO, ModeloTablaContacto se utilizan sin modificación.

Opcional:

  • Es posible modificar el método isCellEditable() de la clase ModeloTablaContacto para limitar el valor introducido del número de contacto en la última fila de la tabla.

  • Sustituir JDesktopPane por JDesktopPaneMG, sustituir JScrollPane por JScrollPaneMG en la clase Ventana principal. Es más bonito.

d. Documentación

No dude en consultar la Javadoc de las clases para la utilización de las ventanas internas: JDesktopPane, JInternalFrame, InternalFrameEvent.

JDesktopPane es un panel especial destinado a contener las ventanas internas (JInternalFrame). Podemos utilizarlo como un JPanel

La escritura de una ventana interna (clase heredada de JInternalFrame) recuerda mucho a cómo se hace con una ventana principal (heredada de JFrame). Hay que gestionar los InternalFrameEvent en lugar de los WindowEvent.

La clase utilizada para mostrar una ventana modal es JOptionPane.

3. GestionContactoLocal: propuesta de corrección

a. Diagrama de secuencia

images/Esquema.png
  1. El usuario arranca la aplicación: se ejecuta el método main() de la clase Controlador

  • El método main() instancia la Ventana.

  • El usuario solicita los contactos pulsando el ítem Contacto del menú.

  • La Ventana llama al método solicitarContactos() del Controlador.

  • El Controlador llama al método crearListaContactos...