UNIVERSIDAD DE EL SALVADOR ESCUELA DE INGENIERIA DE SISTEMAS INFORMATICOS PROGRAMACION III PROGRAMACION EN JAVA JAVA SWING PARTE I Contenido Java Swing ................................................................................................................................................ 1 Mensajes de diálogo .............................................................................................................................. 1 Ejemplo Login....................................................................................................................................... 4 JFrame ................................................................................................................................................... 5 JLable .................................................................................................................................................... 7 JTextField .............................................................................................................................................. 9 JButton ................................................................................................................................................ 12 Componentes personalizados .................................................................................................................. 13 El administrador de disposición (Layout Manager) ............................................................................ 16 Eventos ................................................................................................................................................ 20 Ejemplo1 Registro de huéspedes ............................................................................................................ 22 TableModel ......................................................................................................................................... 25 Java Swing Los programas que utilizan exclusivamente interfaces de usuario través de System.in y System.out son llamados programas de consola. Los programas basados en interfaces gráficas (Graphical User Interfaces, GUI) en Java son desarrollados a través de un conjunto de clases de los paquetes estándar javax.swing y java.awt. Estos programas son usualmente llamados programas de escritorio. Los programas de escritorio utilizan una serie de ventas para su funcionamiento. Un ejemplo de este tipo de entornos es el mostrado en la figura 1.1. JFrame JMenu JLabel JText JButton Figura 1.1: Formulario realizado con Swing con algunos componentes de la librería Mensajes de diálogo Una forma intuitiva de escribir programar con entorno de ventanas, es usando la case JOptionPane, que ya hemos utilizado en laboratorios anteriores. El código JOptionPane.showMessageDialog(null, “Programación III); Nos permite mostrar una ventana en la que podemos mostrar un contenido en forma de String. 1 Para conocer las constantes, atributos y métodos de los que consta alguna clase de Java, basta con consultar el API (Application Programming Interface) de dicha clase. NetBeans integra la documentación disponible para las clases en su ayuda contextual. Sin embargo, para que Netbeans pueda mostrar la documentación de dicha clase, la librería donde se encuentra dicha clase debe incluir dicha documentación. En la ventana de edición de Netbeans podemos acceder a las declaraciones de los métodos escribiendo parcialmente el comando y presionando control+spacebar Otra forma de acceder a la documentación puede ser consultado a través de Intenet, en la dirección: http://docs.oracle.com/javase/7/docs/api/ 2 En el API puede observarse que el método showMessageDialog es un método sobrecargado. Es decir, que tiene varias definiciones y puede ser utilizado de varias formas. El API de un conjunto de clases en Java generalmente generado a través del paquete Javadoc, que utiliza la documentación realizada por el programador para generar la documentación en formato html. La forma trivial del método showMessageDialog tiene la siguiente descripción Brings up an informationmessage dialog titled “Message” (Muestra un cuadro de diálogo de información o mensaje con el título “Mensaje”). Recibe como parámetros la variable parentComponent (componente padre), de tipo Component, que determina el Frame (ventana) en la que el dialogo será mostrado. Si es null, o si el parentComponent no tine Frame, será usado el Frame por defecto. El parámetro message, de tipo Object es el mensaje que se desplegará. En este caso, hemos enviado null al parámetro parentComponent (componente padre), lo que significa que la ventana será mostrada de forma independiente de cualquier otra ventana que se esté mostrando. 3 Para leer valores desde un cuadro de diálogo usamos el método showInputMessage, que despliega un cuadro de diálogo con una cuadro de texto que permite ingresar valores. Sin embargo, el valor leído por le método y devuelto como valor de retorno es de tipo String. Para resolver el problema de los valores numéricos, se utilizan las llamadas clases de envoltorio (Wrapper) que permiten convertir valores String a tipos primitivos o en algunos casos objetos de dichas clases. Los métodos más usados para realizar esta conversión se describen en la tabla 1.1 Clase Tabla 1.1: Métodos para conversión de valores en formato String a formatos numéricos. Método Ejemplo Integer parseInt Integer.parseInt(“25”) → 25 Integer.parseInt(“25.3”) → error Long parseLong Long.parseLong(“25”) → 25L Long.parseLong(“25.3”) → error Float parseFloat Float.parseFloat(“25.3”) → 25.3F Float.parseFloat(“ab3”) → error Double parseDouble Double.parseDouble(“25”) → 25.0 Double.parseDouble(“ab3”) → error String sNota = JOptionPane.showInputDialog("¿Cuánto sacaste en el examen de Programación III?"); float fNota = Float.parseFloat(sNota); JOptionPane.showMessageDialog(null, fNota); Para desarrollar aplicaciones de escritorio más completas, otras clases del paquete de clases javax.swing, que permiten crear interfaces de usuario más complejas. Ejemplo Login Construyendo un formulario Supongamos que tenemos el siguiente caso de uso como requerimiento para un programa. 4 Nombre: Ingresar al sistema Autor: PRN315 Descripción: Verificar las credenciales de acceso al sistema para permitir su acceso. Actores: Usuario Precondiciones: Flujo normal de los eventos: 1. El usuario solicita el ingreso al sistema 2. El sistema muestra la pantalla de ingreso con el nombre del usuario y la clave. 3. El actor ingresa los datos solicitados 4. Los datos son válidos, el sistema despliega el mensaje: Bienvenido al sistema Flujos alternativos: 4.1 Las credenciales no son correctas, el sistema despliega el mensaje: Ud. no tiene las credenciales necesarias para ingresar. Postcondiciones: JFrame La clase JFrame es usada principalmente como contenedor de otros componentes Swing. Crearemos un JFrame al que iremos incorporando los elementos solicitados por el enunciado. Usaremos el constructor de JFrame que recibe como parámetro una cadena de caracteres como el título del JFrame. Si consultamos el API de la clase JFrame, veremos que cuenta con un método setSize, donde uno de sus formas, recibe dos parámetros que conformarán el tamaño de la ventana en pixeles. 5 package prn315.guia03; import javax.swing.JFrame; public class EjemploFrame { public static void main(String[] args){ JFrame frame = new JFrame("Pantalla de ingreso al sistema"); frame.setSize(300, 300); frame.setVisible(true); } } La ventana que hemos construido hasta ahora se verá como se muestra en la figura 2.1 Figura 2.1 Frame con título y sin contenido La apariencia del frame está basada en el tema del sistema operativo sobre el que está ejecutándose el programa. Para usar la decoración por defecto de las interfaces Java, debemos invocar al método estático setDefaultLookAndFeelDecorated. Por ser un método de clase, esta configuración será aplicada a todos los Frames que sean generados por el programa. 6 JLable JLabel es una extensión de JComponent, por lo que tiene todas las características de un componente Swing. Crearemos el label usando el constructor que recibe como parámetro el texto a mostrar. Una vez creado, agregaremos el label al frame a través del método add, donde una de sus implementaciones recibe como parámetro un componente. public class EjemploFrame { public static void main(String[] args){ final int FRAME_WITH = 300; final int FRAME_HEIGTH = 300; JFrame.setDefaultLookAndFeelDecorated(true); JFrame frame = new JFrame("Pantalla de ingreso al sistema"); frame.setSize(FRAME_WITH, FRAME_HEIGTH); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); JLabel lUsuario = new JLabel("Nombre de usuario: "); frame.add(lUsuario); } } Este es un ejemplo muy práctico del polimorfismo, ya que el método add utilizado, recibe como parámetro un objeto de tipo Component, pero en nuestro código estamos agregando un objeto de tipo JLabel. Esto es posible debido a que JLabel es una clase derivada de Component (una herencia de tercer nivel). Cualquier objeto de una clase que herede de Component puede ser enviada como parámetro al método add. 7 El frame resultante después de los cambios tendrá la forma que se muestra en la figura 2.2 Figura 2.2 Frame de ingreso al sistema, con label para el nombre del usuario. Nótese que también hemos establecido el cierre del programa, como la operación por defecto al cerrar el frame (setDefaultCloseOperation). Esto es útil puesto que si no se establece esa acción, el programa quedará ejecutándose aunque ya no veamos el frame. 8 JTextField De una forma similar a como se agregó el label, agregaremos un campo de texto para capturar el nombre del usuario. public class EjemploFrame { public static void main(String[] args){ final int FRAME_WITH = 300; final int FRAME_HEIGTH = 300; JFrame.setDefaultLookAndFeelDecorated(true); JFrame frame = new JFrame("Pantalla de ingreso al sistema"); frame.setSize(FRAME_WITH, FRAME_HEIGTH); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); JLabel lUsuario = new JLabel("Nombre de usuario: "); JTextField tUsuario = new JtextField(“Ingrese aquí el usuario”); //Agregando componentes creados frame.add(lUsuario); frame.add(tUsuario); } } Al ejecutar este código, ocurre un problema con el orden en que se muestran los componentes. El frame únicamente muestra el campo de texto que es visible gracias a que se usó el constructor que le entrega un texto por defecto. Para resolver esto, debemos acudir al administrador de la disposición de los componentes. Usando el layout básico para un componente JFrame. 9 public class EjemploFrame { public static void main(String[] args){ final int FRAME_WITH = 300; final int FRAME_HEIGTH = 300; JFrame.setDefaultLookAndFeelDecorated(true); JFrame frame = new JFrame("Pantalla de ingreso al sistema"); frame.setSize(FRAME_WITH, FRAME_HEIGTH); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JLabel lUsuario = new JLabel("Nombre de usuario: "); JTextField tUsuario = new JTextField("Ingrese aquí el usuario"); frame.setLayout(new FlowLayout()); //Agregando componentes creados frame.add(lUsuario); frame.add(tUsuario); frame.setVisible(true); } } Figura 2.3 Frame de ingreso al sistema con dos controles. 10 Agregaremos ahora un campo de texto para capturar el password del usuario y un label que indique que se trata de un control para el password. public class EjemploFrame { public static void main(String[] args) { final int FRAME_WITH = 300; final int FRAME_HEIGTH = 300; JFrame.setDefaultLookAndFeelDecorated(true); JFrame frame = new JFrame("Pantalla de ingreso al sistema"); frame.setSize(FRAME_WITH, FRAME_HEIGTH); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JLabel lUsuario = new JLabel("Nombre de usuario:"); JTextField tUsuario = new JTextField("Ingrese aquí el usuario"); JLabel lPassword = new JLabel("Password:"); JTextField tPassword = new JTextField("Ingrese aquí el password"); frame.setLayout(new FlowLayout()); //Agregando componentes creados frame.add(lUsuario); frame.add(tUsuario); frame.add(lPassword); frame.add(tPassword); frame.setVisible(true); } } 11 JButton La clase JButton permite crear componentes de tipo botón. Al igual que el resto de los componentes usados hasta ahora, cuenta con una serie de constructores dentro de los que se encuentra un constructor que recibe como parámetro el texto que se mostrará con el botón. Usaremos este constructor para agregar los botones Aceptar y Cancelar al formulario. public class EjemploFrame { public static void main(String[] args) { final int FRAME_WITH = 300; final int FRAME_HEIGTH = 300; JFrame.setDefaultLookAndFeelDecorated(true); JFrame frame = new JFrame("Pantalla de ingreso al sistema"); frame.setSize(FRAME_WITH, FRAME_HEIGTH); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JLabel lUsuario = new JLabel("Nombre de usuario:"); JTextField tUsuario = new JTextField("Ingrese aquí el usuario"); JLabel lPassword = new JLabel("Password:"); JTextField tPassword = new JTextField("Ingrese aquí el password"); JButton bAceptar = new JButton("Aceptar"); JButton bCancelar = new JButton("Cancelar"); frame.setLayout(new FlowLayout()); //Agregando componentes creados frame.add(lUsuario); frame.add(tUsuario); frame.add(lPassword); frame.add(tPassword); frame.add(bAceptar); frame.add(bCancelar); frame.setVisible(true); } } 12 Figura 2.4 Frame de ingreso al sistema, con controles de entrada. Componentes personalizados Hasta ahora hemos creado una clase a través de la cual hemos creado un frame y agregado controles Swing a él. Sin embargo, si quisiéramos utilizar este frame más de una vez y personalizarlo para cada ocasión, deberemos crear copiar el código que hemos escrito cuantas veces lo necesitamos y personalizarlo. Para resolver este problema, podemos extender los componentes Swing para crear nuestros propios componentes. La creación de componentes personalizados se realiza extendiendo los componentes básicos Swing. 13 package prn315.guia03; import java.awt.FlowLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextField; public class EjemploFrameExtendido extends JFrame { final int ANCHO = 300; final int ALTO = 300; private JLabel lUsuario; private JTextField tUsuario; private JLabel lPassword; private JTextField tPassword; private JButton bAceptar; private JButton bCancelar; public EjemploFrameExtendido(String titulo) { super(titulo); initComponent(); } ... 14 private void initComponent() { lUsuario = new JLabel("Nombre de usuario:"); tUsuario = new JTextField("Ingrese aquí el usuario"); lPassword = new JLabel("Password:"); tPassword = new JTextField("Ingrese aquí el password"); bAceptar = new JButton("Aceptar"); bCancelar = new JButton("Cancelar"); setSize(ANCHO, ALTO); setLayout(new FlowLayout()); add(lUsuario); add(tUsuario); add(lPassword); add(tPassword); add(bAceptar); add(bCancelar); } } package prn315.guia03; public class TestFrameExtendido { public static void main(String[] args){ EjemploFrameExtendido frame = new EjemploFrameExtendido("Pantalla principal"); frame.setVisible(true); } } Con el código anterior logramos la misma pantalla. Sin embargo, hemos construido nuestro propio componente Swing, que podríamos utilizar de múltiples formas y proyectos. 15 El administrador de disposición (Layout Manager) Hemos definido el ancho del frame en 300 pixeles, lo que hace que los componentes que se agregan al frame tengan una disposición aceptable para el tipo de formulario que estamos editando. Sin embargo, si ampliamos el ancho del frame, los componentes van alineándose horizontalmente debido a que la disposición configurada a través de la clase FlowLayout no permite configurar una disposición en filas y columnas. Existen varias clases para realizar esta configuración. Sin embargo, la clase que ofrece más flexibilidad para este fin es la clase GroupLayout, que aunque muy útil, resulta muy compleja en cuanto a su uso. package prn315.guia03; import java.awt.FlowLayout; import javax.swing.GroupLayout; import javax.swing.GroupLayout.Alignment; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextField; public class EjemploFrameExtendido extends JFrame { final int ANCHO = 300; final int ALTO = 300; private JLabel lUsuario; private JTextField tUsuario; private JLabel lPassword; private JTextField tPassword; private JButton bAceptar; private JButton bCancelar; public EjemploFrameExtendido(String titulo) { super(titulo); initComponent(); } private void initComponent() { lUsuario = new JLabel("Nombre de usuario:"); tUsuario = new JTextField("Ingrese aquí el usuario"); lPassword = new JLabel("Password:"); tPassword = new JTextField("Ingrese aquí el password"); bAceptar = new JButton("Aceptar"); bCancelar = new JButton("Cancelar"); ... 16 setSize(ANCHO, ALTO); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); GroupLayout layout = new GroupLayout(getContentPane()); setLayout(layout); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(true); GroupLayout.SequentialGroup hGroup = layout.createSequentialGroup(); hGroup.addGroup(layout.createParallelGroup().addComponent(lUsuario).addComponent(lPassword).addComponent(bAcept ar)); hGroup.addGroup(layout.createParallelGroup().addComponent(tUsuario).addComponent(tPassword).addComponent(bCanc elar)); layout.setHorizontalGroup(hGroup); GroupLayout.SequentialGroup vGroup = layout.createSequentialGroup(); vGroup.addGroup(layout.createParallelGroup(Alignment.BASELINE).addComponent(lPassword).addComponent(tPassword) ); vGroup.addGroup(layout.createParallelGroup(Alignment.BASELINE).addComponent(lUsuario).addComponent(tUsuario)); vGroup.addGroup(layout.createParallelGroup(Alignment.BASELINE).addComponent(bAceptar).addComponent(bCancelar)); layout.setVerticalGroup(vGroup); } } Figura 2.3 Frame extendido de ingreso al sistema Hasta ahora hemos realizado nuestro formulario escribiendo nuestro propio código, lo que resulta no solamente complejo, sino además podría requerir mucho tiempo de trabajo. Por ello, los IDEs de programación, en nuestro caso NetBeans, nos ofrecen entornos de diseño de formularios, que nos permiten crear formularios de forma gráfica. 17 Cuando creamos un formulario en este entorno, el IDE se ocupa de generar el código necesario para que el formulario funcione adecuadamente. Para crear un formulario análogo al que hemos creado, debemos crear no una clase Java tradicional, sino un formulario JFrame. Para ello, hacer clic derecho en el nodo del paquete en el que queremos crear nuestro formulario, elegir la opción Other (Otros). En el cuadro de diálogo que aparece, debemos elegir la opción Swing GUI Forms y en el panel de la derecho elegir JFrame Form. En este entorno nos aparece una pestaña llamada Paleta de controles donde el IDE nos permite elegir los controles que deseamos usar. Para agregar un componente al formulario, basta con elegirlo de la paleta y arrastrar el puntero del ratón al lugar donde lo queremos colocar. El IDE además nos mostrará las propiedades del objeto que se encuentre seleccionado, por defecto debajo de la paleta de controles. Puede observarse que el área de trabajo consta de tres pestañas para la edición del formulario: Source (o Fuente) que muestra el código fuente de nuestro formulario, Design (Diseño) que permite realizar el diseño del formulario a través de los controles que se encuentran en la paleta y History (Historial), que permite ver los cambios realizados en el código. Al seleccionar el frame, podemos observar las propiedades que se encuentran disponibles en tiempo de diseño. Entre estas propiedades está el título (title) del frame. Algo que hicimos en el ejemplo anterior a la hora de construir el frame. 18 Entre otras cosas, el entorno de edición nos permite definir la posición específica de los componentes que agregamos y sus propiedades. 19 Para verificar como se verá en tiempo de ejecución el formulario, no es necesario ejecutar el proyecto, basta con presionar el botón Previsualizar el diseño que nos mostrará la ventana que estamos editando. Eventos Un evento es una acción realizada por alguno de los actores del sistema: llenar un campo de texto, redimensionar una ventana, hacer clic en un botón, etc. El modelo utilizado por Java para manejar los eventos es llamado Modelo de delegación de eventos. En este modelo, los eventos son implementados en dos tipos de objetos: objetos que originan eventos y objetos que escuchan eventos. Un objeto GUI, como un botón, es un objeto de tipo origen de eventos. Si un usuario hace clic sobre el botón, este generará un evento (action event). Un objeto escuchador de eventos o simplemente escuchador de eventos es el objeto en el que se encuentran definidos los métodos que se ejecutarán en respuesta a ese evento. También es posible encontrar ambos comportamientos en un mismo objeto. En el formulario que ya hemos construido, programaremos la respuesta que dará el sistema al evento clic del botón aceptar. Si el nombre del usuario es alumno y la clave prn315 (no importando si es minúscula o mayúscula), deberá de mostrar el mensaje: “Bienvenido al sistema”. Si se escribe cualquier otra combinación, el formulario deberá desplegar el mensaje: “Ud. no tiene las credenciales para entrar”. Para programar el evento, hacemos clic derecho sobre el botón aceptar y elegimos la opción Events (Eventos), Actions (Acciones) y ActionPerformed (Acción a realizar), en el entorno de diseño del formulario. NetBeans nos creará un método llamado jButton1ActionPerformed que recibe como parámetro un objeto de la clase ActionEvent, ya que este es el tipo de evento que se genera con el clic en el botón. Nótese que en este caso, el botón es un objeto generador de eventos, el mismo botón se convierte en el escuchador de eventos a través del método recién creado, por lo que requiere recibir un objeto de tipo evento. 20 private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: if(jTextField1.getText().toUpperCase().equals("ALUMNO") && jTextField2.getText().toUpperCase().equals("PRN315")){ JOptionPane.showMessageDialog(this, "Bienvenido al sistema"); }else{ JOptionPane.showMessageDialog(this, "Ud. no tiene las credenciales para entrar"); } } Nótese que en este caso, hemos enviado como componente padre del mensaje al frame que estamos editando, por lo que el cuadro de diálogo se mostrará como una ventana interna del frame, y no independiente como ocurría cuando le enviamos null como parámetro. 21 Ejemplo1 Registro de huéspedes Nombre: Registrar cliente Autor: PRN315 Descripción: Permite registrar a un cliente que desea hospedarse en el hotel Actores: Recepcionista Precondiciones: El actor debe haberse logeado en el sistema Flujo normal de los eventos: 1 .El actor ingresa al sistema para ver si existen habitaciones disponibles 2. El sistema muestra una lista con las habitaciones que se encuentran disponibles con los siguientes datos: Número de habitación, Nivel en el que se encuentra, Tipo de habitación: Doble, Sencilla o Triple y el precio por defecto. 3. El actor selecciona la habitación que desee reservar/entregar al cliente. 4. El sistema muestra una pantalla de registro del cliente, en la que deberá de ingresarse: Nombre del cliente, Fecha y Nacionalidad. 5. El actor ingresa los datos solicitados y guarda la información. 6. El sistema muestra un mensaje de confirmación. Flujos alternativos: 3.1 No hay habitaciones disponibles, se cancela la operación. 4.1 El actor cancela la operación. 4.2 El sistema muestra el mensaje “Operación cancelada por el usuario” Postcondiciones: Primero diseñaremos el formulario de consulta. Para simplificar el problema, asumiremos que la consulta siempre mostrará las habitaciones disponibles. Llamaremos a este formulario ConsultaHabitaciones. 22 El formulario deberá tener un label con el texto Habitaciones disponibles y una tabla de cuatro columnas. Usaremos el componente JTable para mostrar los datos. Al hacer clic derecho sobre la tabla, y elegir la opción Table content (o Contenido de la tabla), aparecerá un cuadro de diálogo que permite especificar el contenido que mostrará la tabla. La opción por defecto es User specified (especificado por el usuario). Esto habilita la definición de la cantidad de columnas y la cantidad de filas que tendrá la tabla y sus valores. 23 24 Este método, aunque sencillo, hace que los valores que hemos ingresado en el cuadro de diálogo sean mostrados en todas la ejecuciones, y que además, no sean susceptibles a cambios, hasta el momento de la ejecución del formulario, siempre que sea programado un evento para ello. El código que permitiría agregar una fila con datos, al hacer clic sobre un botón que llamaremos jBAgregarFila, se muestra a continuación. private void jBAgregarFilaActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: DefaultTableModel temp = (DefaultTableModel) jTable1.getModel(); Object nuevo[] = {"5D", new Integer(5), new Integer(3), new Double(50)}; temp.addRow(nuevo); } TableModel Para que los datos mostrados por la tabla sean dinámicos, usaremos un TableModel (modelo de tabla), que define las características que debe cumplir un conjunto de datos, para poder ser mostrados por la tabla. Para ello, definiremos como modelo de la tabla el tipo Custom code (código personalizado), y asignaremos al modelo de la tabla, la variable modeloHabitaciones. Como es lógico, la variable modeloHabitaciones debe existir en el formulario que estamos editando (que es una clase). Para ello, debemos primero crear la clase ModeloHabitaciones, que debe extender la clase abstracta AbstracTableModel. Una de las características que debe cumplir es tener una colección de habitaciones, que son los datos que se mostrarán. Esa colección puede ser de cualquier clase que implemente la interfaz Iterable (Un arreglo común, un objeto Collection, un objeto List, un objeto Iterator, etc). El modelo conceptual de clases que necesitaremos programar para resolver de esta forma el problema, se muestra a continuación. 25 Podemos observar que se requiere la programación de una clase Habitación, una clase que de soporte al modelo de la tabla específicamente para las habitaciones, y una clase principal para ejecutar el programa. 26 package prn315.guia03.ejemplohotel; public class Habitacion { private String numero; private int nivel; private int tipo; private double precio; public String getNumero() { return numero; } public void setNumero(String numero) { this.numero = numero; } public int getNivel() { return nivel; } public void setNivel(int nivel) { this.nivel = nivel; } public int getTipo() { return tipo; } public void setTipo(int tipo) { this.tipo = tipo; } public double getPrecio() { return precio; } public void setPrecio(double precio) { this.precio = precio; } } 27 package prn315.guia03.ejemplohotel; import java.util.ArrayList; import java.util.List; import javax.swing.table.AbstractTableModel; public class HabitacionTableModel extends AbstractTableModel{ List<Habitacion> habitaciones = new ArrayList<Habitacion>(); private String tiposHabitacion[] = {"Sencilla", "Doble", "Triple"}; @Override public int getRowCount() { return habitaciones.size(); } @Override public int getColumnCount() { return 4; } @Override public Object getValueAt(int rowIndex, int columnIndex) { Object valor = null; switch(columnIndex){ case 0: valor = habitaciones.get(rowIndex).getNumero(); break; case 1: valor = habitaciones.get(rowIndex).getNivel(); break; case 2: int iTipo = habitaciones.get(rowIndex).getTipo(); valor = tiposHabitacion[iTipo-1]; break; case 3: valor = habitaciones.get(rowIndex).getPrecio(); } return valor; } } 28 En el formulario que ya hemos creado, al que hemos llamado ConsultaHabitaciones, debemos agregar el atributo modeloHabitaciones, como se muestra en el siguiente código. package prn315.guia03.ejemplohotel; import javax.swing.table.DefaultTableColumnModel; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; public class ConsultaHabitaciones extends javax.swing.JFrame { /* * Atributo modeloHabitaciones, usado con modelo de la tabla */ HabitacionTableModel modeloHabitaciones = new HabitacionTableModel(); Para ejecutar el proyecto deberemos programar la clase Principal, con el siguiente código. 29 package prn315.guia03.ejemplohotel; import java.util.Random; public class Principal { public static void main(String[] args) { final String[] UNIDADES = {"A ", "B", "C", "D", "E"}; Random random = new Random(new Long(13)); ConsultaHabitaciones consultas = new ConsultaHabitaciones(); for (int i = 0; i< 5; i++) { Habitacion habitacion = new Habitacion(); habitacion.setNivel(i + 1); habitacion.setNumero(UNIDADES[i] + (i+2)); habitacion.setTipo(1); habitacion.setPrecio(random.nextDouble() * 105); consultas.modeloHabitaciones.habitaciones.add(habitacion); } consultas.setVisible(true); } } Nótese que el lazo for sirve para generar objetos de habitaciones de forma dinámica, que son agregados a la lista de habitaciones, que será asignado posteriormente al objeto del modelo que deberá mostrarlos. Al ejecutar el programa, mostrará la pantalla que se muestra a continuación. 30 Nótese que los encabezados de las columnas tienen valores A, B, C y D. Esto ocurre porque no se han definido los títulos de las columnas del modelo de tabla. Para resolver este problema, agregaremos un método de inicialización de los encabezados de las columnas de la tabla, como se muestra a continuación. 31 public class ConsultaHabitaciones extends javax.swing.JFrame { HabitacionTableModel modeloHabitaciones = new HabitacionTableModel(); /** * Creates new form ConsultaHabitaciones */ public ConsultaHabitaciones() { initComponents(); inicializarColumnas(); } private void inicializarColumnas() { TableColumnModel tColumnModel = new DefaultTableColumnModel(); for (int i = 0; i < 4; i++) { TableColumn col = new TableColumn(i); switch (i) { case 0: col.setHeaderValue("Número"); break; case 1: col.setHeaderValue("Nivel"); break; case 2: col.setHeaderValue("Tipo"); break; case 3: col.setHeaderValue("Precio"); } tColumnModel.addColumn(col); } jTable1.setColumnModel(tColumnModel); } ... 32 Ahora podemos crear el segundo formulario. Que de acuerdo la especificación recibida, deberá permitirnos el ingreso de los datos del cliente y algunos valores adicionales. El formulario que deberemos construir debe tener la siguiente forma. JTextField JComboBox JFormattedTextField JFormattedTextField El contenido del JComboBox lo asignaremos dinámicamente desde el código. Para ello, crearemos un método que llamaremos inicializarTiposClientes. Además, usaremos el valor recibido como parámetro en el constructor del formulario para asignar el valor al label encargado de mostrar la habitación para la que se está haciendo la reservación/asignación (jLabel6). 33 package prn315.guia03.ejemplohotel; import java.util.ArrayList; import java.util.List; import javax.swing.DefaultComboBoxModel; import javax.swing.JOptionPane; public class RegistroCliente extends javax.swing.JFrame { List<String> tipos = new ArrayList<String>(); /** * Creates new form RegistroCliente */ public RegistroCliente(String habitacionSeleccionada) { initComponents(); iniciarlizarTiposCliente(); jLabel6.setText(habitacionSeleccionada); } private void iniciarlizarTiposCliente() { tipos = new ArrayList<String>(); tipos.add("Primera vez"); tipos.add("Registrado"); tipos.add("Frecuente"); jComboBox1.setModel(new DefaultComboBoxModel(tipos.toArray())); } ... Los controles de tipo JFormattedTextField los configuraremos para que reciban el formato de fecha. Para ello, seleccionamos el control correspondiente y hacemos clic sobre el botón junto a la propiedad formattedFactory. 34 Esto nos mostrará una pantalla en la que debemos especificar el formato de la entrada que recibirá el control. 35 El formulario resultante se muestra a continuación. Ahora podemos programar los eventos de los botones, de acuerdo a la especificación del problema. private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: JOptionPane.showMessageDialog(this, "Se ha registrado al cliente"); } private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: JOptionPane.showMessageDialog(this, "Operación cancelada por el usuario"); this.setVisible(false); this.dispose(); } Una vez creado el segundo formulario, podemos programar el evento en el formulario ConsultaHabitacion, que invoque al formulario recién creado. Para ello, hacemos clic derecho sobre la tabla, elegimos la opción Events (eventos), Mouse (ratón) y mouseClicked. 36 ... private void jTable1MouseClicked(java.awt.event.MouseEvent evt) { int clics = evt.getClickCount(); int row = jTable1.rowAtPoint(evt.getPoint()); HabitacionTableModel habitacionTableModel = (HabitacionTableModel) jTable1.getModel(); //La acción se realizará cuando se realiza un doble clic if(clics == 2){ String habitacionSeleccionada = (String) habitacionTableModel.habitaciones.get(row).getNumero(); RegistroCliente registroCliente = new RegistroCliente(habitacionSeleccionada); registroCliente.setVisible(true); } } ... 37