jueves, 3 de diciembre de 2020

Como Mejorar y completar el prototipo de Ventanas JFRAME Java con persistencia

Como Mejorar y completar el prototipo de Ventanas JFRAME Java con persistencia 

Este tutorial es una continuación de dos anteriores, relacionados con la creación de ventanas JFrame sencillas y rápidamente, metiendo directamente la mano en el código sin wizard (ayudantes de diseño).

Si has llegado aquí sin haber visto lo anterior,  seria conveniente que por lo menos se le diera un vistazo a estos dos siguientes enlaces.

Crear Ventana JAVA JFrame sin layout manualmente


Ventanas JFrame Java con ejemplo de persistencia usando base de Datos Oracle Express

Mejorando y completando el prototipo

Aquí vamos añadir funcionalidad algunos botones mas de las ventanas, que actualmente no hacen nada y añadiremos otro botón a modo de ejemplo. También vamos añadir una o mas funcionalidades según lo requiera el caso

Vamos a empezar por la ventana Menú. El botón Registrar funciona, y abre una ventana, pero el botón Salir no hace nada.
 

Vamos a la parte del código donde están el método que controla estas acciones. Este método es de obligado definición al implementar la interface ActionListener, la cual establece que el método actionPerformed va capturar los eventos de pulsado o click del ratón sobre cualquier elemento en la ventana. Es decir que cada vez que pulsemos sobre algún elemento dentro de la ventana este método se ejecutará y buscará entre las opciones if que definamos, si algúno de ellos coincide y entonces ejecutará la instrucciones que estén declaradas en el cuerpo del if.

Vemos como para el botón btnRegistro está definido y tiene las acciones a seguir en caso de ser pulsado. Vemos además que no hay ningún botón adicional definido.



Ahora vamos a darle funcionalidad el botón Salir, y para ello tenemos que hacer dos cosas, una de ellas es escribir en el método actionPerformed() la acción a realizar cuando sea pulsado el botón Salir y la otra es añadir el evento ActionListener al botón salir.

Vamos a realizar entonces inclusión las siguientes sentencias dentro del método actionPerformed().

if  (e.getSource().equals(btnSalir)){
                System.out.println("Estoy dentro de Salir");
          this.dispose();
 }

Lo anterior simplemente libera la memoria del equipo y termina el programa. También escribe por consola el mensaje de que esta dentro del cuerpo del if que ha determinado que efectivamente el botón pulsado ha sido Salir. Nuestro código quedaría así:




Ahora vamos añadir el evento ActionListener al botón Salir, que fue definido en el método componentes().

Veamos primero como está el método componentes sin hacerle la modificación necesaria:
 

Como sugieren las flechas, falta poner la sentencia:

btnSalir.addActionListener(this);

Escribimos la sentencia quedando el código así:


Ahora vamos a probar el código y vamos a la clase Inicio a ejecutarlo. Debes obtener el menú que luego de pulsar sobre Salir debe quedar igual o similar a la imagen siguiente:

Hemos comprobado que ya tiene funcionalidad el botón Salir y que además es correcto su funcionamiento, cierra la ventana y termina la ejecución del programa.

Ya con lo visto estamos en capacidad de añadir mas botones al menú y asociarles funcionalidad.

Podemos dar más funcionalidad al menú con el objeto de ayudar al usuario a realizar sus tareas, como por ejemplo cuando un botón reciba el foco, o sea, que el cursor del ratón se coloque encima, se active un mensaje que describa la acción que ejecuta.

Vamos hacerlo paso a paso, primero implementamos la interface MouseListener en la clase Menu:


Al añadirlo notamos que el IDE (NetBeans, Eclipse...), marca un error y si pulsamos con el ratón encima del mismo nos salta un pequeño rectángulo dando dos opciones a seguir, y de entre las cuales vamos a escoger Add import..., lo cual añade la librería necesaria.


Vemos que a pesar de que hemos importado la librería, sigue marcando un error y pulsando sobre el mismo vemos que hay dos opciones de solución. Como la interface MouseListener tiene métodos abstractos, estos deben definirse o marcar la clase como abstracta. Por supuesto, escogemos implements all abstract methods y pulsamos sobre esa opción. Veremos como los métodos son añadidos que justo en este caso lo hace debajo de los métodos que capturan los eventos ActionListener.

Como vemos el MouseListener, tiene mas métodos que ActionListener pero nosotros vamos a utilizar solamente dos para los que nos hemos planteado. Debemos saber además que está acción de incorporar los métodos, ha provocado que el IDE (NetBeans, Eclipse...), importara además la librería de eventos correspondiente, si vemos nuestra clase de nuevo al principio veremos:


Estos detalles se nos escapan cuando somos novatos, que no se nos escaparían tan fácilmente, si usamos un editor de texto sin ayuda de ningún tipo, ya que simplemente tendríamos que conocer de antemano todos estos detalles e ir compilando y mirando los errores e interpretarlos. Editores como NetBeans, Eclipse, VS Code y otros son una gran ayuda a la hora de escribir código JAVA, pero también hay ocasiones en donde debemos mirar muy bien que es lo que escogemos porque en ocasiones las alternativas son menos obvias y puede que no sea tan fácil interpretar que debemos escoger.

Vamos a dar a ahora el siguiente paso, que es definir la etiqueta que contendrá el mensaje que deseemos según sea el botón sobre el cual se posa el puntero del ratón. Añadimos la etiqueta labelMensaje:


A continuación tendremos que establecer en que lugar del código del menú queremos definir los datos que daremos a la etiqueta, vamos al método componentes(), y escribimos en el lugar elegido:


Hemos escrito al definición de la etiqueta justo encima de la definición del botón salir, creamos el objeto labelMensaje con new JLabel(), le especificamos en que lugar del menú va a salir el mensaje setBounds(x, y, ancho, alto), donde  x=distancia del borde izquierdo al principio del mensaje 40, y= distancia del borde superior del menú al cuerpo del mensaje, ancho del mensaje y altura de la fuente. Finalmente con add(), añadimos la etiqueta al JFrame.

Una vez que hemos escrito el código en el método componente, ya estamos preparados para mostrar los mensajes dependiendo sobre que botón pase el puntero del ratón.

Vamos entonces a programar dos métodos de los implementados por la interface MouseListener, mouseEntered() y mouseExited(). Empezamos por el método que captura el evento de pasar el puntero del razón sobre el botón, que es mouseEntered y luego seguimos con mouseExited.

En el método mouseEntered este será el código:

public void mouseEntered(MouseEvent e) {
    if(e.getSource().equals(btnRegistro)){
       
        labelMensaje.setText("Para insertar un nuevo registro en la tabla  agenda");
        labelMensaje.setVisible(true);
        }  
    }

En el método mouseExited este será el código:

public void mouseExited(MouseEvent e) {
         if(e.getSource().equals(btnRegistro)){
       
            labelMensaje.setText("");
            labelMensaje.setVisible(false);
        }      
    }



Si corremos el programa veremos como al pasar el puntero del ratón sobre el botón Registrar, se escribe el mensaje sobre el botón Salir.

Podemos apreciar que nuestro mensaje esta cortado. Este lo podemos corregir, ampliando el ancho en setBounds, pero vemos también que quedaría muy justo, así que habrá que ajustar también el eje X. Eso se lo dejamos de tarea para que se vayamos probando y acostumbrando a las medidas que deben usarse.

Vamos ahora a eliminar o comentar las sentencias, que se encuentran en los metodos que ha sido añadidos por las interfases:

throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.

Que tienen los métodos, ya que esto lo que hace es enviar un error, que no vamos a manejar y no viene al caos cuando el método no se utiliza.

En nuestro caso vamos a eliminarlos y así limpiamos el código.

Ahora rápidamente vamos a mostrar como añadir un botón más. Copiamos el botón registrar así, marcamos todo el bloque btnRegistro y una vez marcado pulsamos el botón derecho sobre el área resaltada y pulsamos sobre la opción Copy:


Ahora simplemente hacemos espacio entre el bloque btnRegistro y el bloque labelMensaje, de tal forma de dejar un espacio de tres lineas y nos colocamos en el medio pulsamos el botón derecho del ratón y luego pulsamos en la opción Paste:



Quedando algo igual o similar a lo siguiente:

Ahora simplemente lo que tenemos que hacer es cambiar el nombre del botón. Vamos a usar el siguiente btnModificar. Una vez hecho esto es lo que debe quedarnos:


Vemos como se muestran errores en todas la lineas y estos son debido a que todavía no hemos declarado btnModificar como una variable del tipo JButton. Es decir estamos tratando de instanciar el objeto btnModificar antes de declararlo. Pues justo lo que hace falta entonces es declararlo y ya tendremos nuestro botón. Vamos entonces al lugar donde estamos declarando estos botones y lo añadimos simplemente y vemos como desaparecen los errores:


Pero cuidado!!
El método setBounds() de los dos botones tiene los mismos valores, lo cual no puede ser ya que se solapan. Además el valor del método setText es el mismo también. Vamos a cambiar el setBounds simplemente escribiendo 80 en los que sería el eje Y, o sea setBounds(120, 80, 150, 20) y cambiamos el setText por setText("Modificar"), lo cual debe quedar así:


Si ahora corremos el programa, veremos algo como lo siguiente:


Como podemos apreciar de aquí en adelante todo es prácticamente un copiar y pegar y luego modificar y adaptar a la nueva situación. Eso quiere decir que estamos en capacidad de modificar tamaños, contenidos y funcionalidades. Sabemos ademas que uno de los objetivos que era grabar en una base de datos, funciona. Lo que queda es ir creciendo de forma paulatina y controlada.

Evidentemente nos vemos siempre en la necesidad de buscar soluciones para cuestiones específicas, ya que no es lo mismo insertar un nuevo registro que modificarlo. Modificar un registro se vuelve algo mucho mas complejo ya que hay que leer previamente el registro, luego mostrarlo en las casillas correspondientes del formulario, luego esperar que algo sea modificado o no y luego finalmente volver a grabar el registro con la nueva modificación.

Ahora vamos a ver que podemos mejorar en la clase Registro, que es la ventana que muestra un formulario de inserción de registros. Vamos a ver que tenemos en la ventana Registro:


Si pulsamos el botón Cancelar veremos que el mismo no funciona, cuando lo normal es que cierre la ventana y no grabe nada. De paso debemos indicar que existe un error lógico al momento de Guardar y es que si dejamos en blanco el formulario el mismo puede ser grabado, lo cual no tiene sentido.

Vamos a darle funcionalidad al botón Cancelar. Vamos a la clase Registro y los dirigimos al método actionPerformed(), que como ya debemos saber captura los eventos del pulsado del ratón asociado a un elemento tipo botón y vamos a añadir el código sombreado en azul.


Ahora vamos al método componentes() y buscamos donde está definido el botón btnCancelar, y verificamos que existe la sentencia btnCancelar.addActionListener(this), para generar el evento, si no existe la añadimos.


Ahora probamos lo que hemos hecho corriendo el programa y veremos que funciona, porque cierra el formulario y retorna a la ventana Menu. Fácil, no?

Si analizamos el código utilizado la acción que ejecuta el programa al pulsar Cancelar en la ventana Registro se limita a dos lineas, pero si observamos el btnGuardar vemos que hemos hecho un truco, con el único objeto de probar que el programa efectivamente podía guardar sin problemas datos. Hemos definido dentro de la ejecución la asignación de valores a dos campos que deberían obtener sus datos desde un formulario y de la lectura de un objeto.

Vemos como se va complicando el código y eso que apenas estamos tratando solo uno. Vamos a suponer que los datos se deben obtener del formulario, para los cual tendremos que crear dos nuevas casillas y sus etiquetas identificadoras, para el usuario pueda escribir los datos. Vamos a realizarlo y para ello vamos el método componentes() de nuevo.

Copiamos todo el bloque que conforma la casilla Apellidos tanto el txt como el label, y duplicamos dos veces, para luego modificarlos y cambiar las partes correspondiente para que uno sea el campo email y el otro sea el campo telefono que son los campos que reciben los datos en la base de datos.



Vemos claramente que hemos repetido por dos veces el código y hemos puesto comentarios para indicar que vamos a cambiarlo, después de lo cual, debe quedarnos algo similar a lo siguiente:


Ya sabemos por qué se generan errores y es debido a que debemos declarar las variables que referencian a los objetos email y telefono y eso debemos hacerlo al comienzo de la clase como vemos aquí:


Y con esto comprobaremos que los errores han desaparecido, pero aún debemos modificarlos que que tiene valores que no les corresponden, como por ejemplo nombres en el método setText y coordenadas ancho y alto en setBounds. Estaremos un rato cuadrando las nuevas casillas y cambiando los nombres del setText, pero al final debemos tener algo similar a lo siguiente en lo resaltado azul:


Evidentemente que hemos ido probando el código con cada modificación, para ir corrigiendo los errores e imprecisiones luego de lo cual no de quedar algo similar a lo siguiente:

Una vez que estemos satisfechos con el aspecto que deseemos darle, pasaremos ahora a que los campos nuevos agregados sean grabados en la base de datos. Esto lo hacemos ubicándonos en el método actionPerformed(), y dentro del if que captura el botón btnGuardar y localizando las variables que deben recibir los valores de las casillas que acabamos de agregar


Una vez que hagamos el cambio el código deber ser igual al siguiente:


Con esto ya tenemos todo correcto. Observemos que no hemos tenido que ir a la clase que graba los datos, simplemente hicimos el cambio aquí, con lo cual no debe haber problemas a la hora de grabar.

Vamos a probar ahora el programa, rellenando todos los campos y pulsamos sobre Guardar:

 Y vemos que el programa no lanza errores y nos muestra el mensaje de que la Grabación fue efectuada correctamente.


Solo nos queda comprobar en el Servidor Oracle Express para comprobar que los datos escritos en los campos fueron grabados en la tabla correctamente. Vamos acceder a la base de datos y vamos a observar el contenido de la tabla AGENDA.


Podemos comprobar que todo ha sido añadido correctamente.

Vamos hacer ahora otras dos mejoras más que nos ayuden a evitar que se guarden registros vacíos, ya que tal como esta el programa y como se configuró la base de datos, los registros nulos son aceptados sin limitación.

Hay evitar que se guarden los datos de los campos en blanco (algunos campos si pueden ir en blanco y simplemente se eliminan de ser comprobados), y podemos comprobarlo a la hora de pulsar el botón Guardar comprobando cada uno de los campos que se quieran comprobar y asegurarse que los campos obligados tengan datos.

Vamos a establecer que todos los campos menos el campo telefono, deben contener datos. Es decir, el único campo permitido que puede estar vacío a la ahora de guardar los datos en el campo telefono

Ademas vamos hacer la comprobación para que todos los elementos o botones que generen el evento actionPerformed(), que es le evento que se activa al pulsar el botón del ratón, tengan acceso a la misma al guardar el resultado en una variable boolean, que llamaremos vacio.

Vamos a ver el código que hay que añadir en el método actionPerformed(), y en el if que captura si el botón guardar fue pulsado, que es el siguiente:



Vemos  que se han añadido la declaracion boolean de la variable vacio y de una vez se le asigna un valor, que es retornado por el método .isEmpty() asociado al campo txtNombre.getText(). Aquí debemos recordar que el valor retornado por getText(), es un String y que JAVA  considera String un objeto. Si queremos comprobar esto solo tenemso que esbribir en el NetBeans lo siguiente:                 "     ".isEmpty(); y veremos como no lo marca como un error. De hecho todo en JAVA es un objeto.

Luego vemos que hacemos una comparación |= que significa (or igual), o sea que asignará a la variable vacio el resultado de comparar lógicamente el valor que tenga vacio con el valor que retorne el metodo .isEmpty(), el cual será true (verdadero) si el campo esta en blanco(vacío) y mantendrá ese valor mientras exista uno o más campos vacíos. Cuando todo los campos sometidos a evaluación tengan un valor, la variable vacio será igual a false (falso).

Luego dentro del cuerpo del if que evalúa si el botón que ha sido pulsado es Guardar, vemos que hemos escrito otro if que evalúa si la variable vacio, pero negándola, es decir que si la variable tiene un valor true el signo ! lo cambia a false y entonces NO se ejecutará el código contenido en el cuerpo del if. Luego se añade un else que será ejecutado en caso contrario. Dentro del cuerpo de este else se escribe un código para generar una ventana de mensaje al usuario, indicandole que hay campo obligatorios vacíos, no guardar nada y devuelve el control a la ventana Registro y continúa el programa.


Con estas simples modificaciones hemos agregado un control de campos que no deseamos que estén en blanco(vacíos) a la hora de guardar el regsitro.

Lo ideal ahora sería hacer la modificación del botón Cancelar, pero en ese caso para que se le advierta al usuario que ha pulsado Cancelar pero que hay campos con datos, pero lo dejaremos como tarea.

Ahora vamos añadir una ayuda visual al lector para indicarle que campos no pueden estar vacíos. Vamos a ver como.


Añadimos FocusListener en implements como vemos aquí abajo, y pulsamos sobre el error para importar la librería correspondiente.

Luego veremos que sigue mostrándose un error y pulsando otra vez sobre el error vemos que tenemos que definir métodos abstractos de la interface. Pulsamos sobre la opción y los métodos serán añadidos al final de la clase


Aquí vemos los métodos añadidos, llamados focusGained() y focusLost() que básicamente significan ganar y perder el foco respectivamente


Para el propósito de detectar si la casilla a quedado vacía, vamos hacer uso del método focusLost(). El funcionamiento se ejecuta cuando el usuario sale de la casilla, en ese momento se dispara el evento focusLost().

Cuando el programa abra la ventana de Registro, marcará con un color rosa, aquellos campos obligatorios de contener datos. Para obtener este comportamiento lo que tenemos que hacer el colorear el background de las casillas que queremos señalar. Así lo hacemos en nuestro código como podemos ver escribiendo el ḿetodo .setBackground(Color.pink); para cada uno de los campos implicados:


Solo cuando el campo tenga algún valor, su background se tornará blanco en cuanto salgamos de esa casilla,  indicando de esta forma que existe un dato. Esto lo debemos manejar en el ḿetodo focusLost(); que es llamado cuando la casilla pierde el foco.

Vamos entonces al método focusLost() de la clase Registro, y vamos añadir el codigo que vemos en la imagen de abajo:


Vamos analizar el primero que es el campo txtNombres, podemos ver que el primer if analiza que si el campo ha obtenido el foco mediante las sentencias e.getSource() concatenada mediante le punto con .equals(txtNombres), al ser verdadero indica que el cursor esta dentro de ese campo y está intentando salir del mismo. 

Es aquí que hacemos la evaluación de si el campo esta blanco o vacío, capturando el texto que tenga el campo mediante el método txtNombres.getText() concatenándolo con el método .isEmpty(), que enviará un verdadero si lo enviado por el getText() está vacío el campo o falso si el campo tiene algún contenido.

Al ser verdadero se vuelve a pintar de rosa el color de fondo de la casilla del campo vacío, indicando que no hay valores en el mismo, lo contrario la casilla tendrá un color de fondo blanco indicando que hay un valor.

Como podemos ver podemos es una forma sencilla de ayudar al usuario a rellanar campos. Podemos además incluir otras funciones, como son validar los valores. Es decir, detectar si el campo debe tener solo números, evitar caracteres especiales, usar Expresiones Regulares, etc.

Dejamos sin verificar el campo txtEmail, para que sea completado por el lector.

En otras entregadas vamos a ir incluyendo algo de los que hemos mencionado, para demostrar que es relativamente sencillo, crear de cero una Ventana JFrame y tener nosotros totalmente el control sobre ella, sin necesidad de usar un wizard

Como siempre si detectas algún error u omisión, o hacer una observación importante, por favor deja un comentario, para corregir, cambiar los conceptos que sean necesarios. Muchas Gracias por visitar mi blog.

No hay comentarios:

Publicar un comentario

Tu comentario puede ser muy útil, asi que no dudes en dejar el tuyo.
Si es relacionado con algún problema, error. etc. trata de ser muy explicito, y detallar el problema y las circunstancias en las que se produjeron. Si lanza algún error trata de copiarlo y pegarlo junto con una descripción del problema, ya que a veces los errores del sistema no son en realidad la causa del problema.

Vistas de página en total