lunes, 26 de octubre de 2020

Componentes básicos de Java Swing

Los componentes básicos que provee la biblioteca Java Swing son

  • JButton
  • JCheckBox
  • JLabel
  • JTextArea
  • JTextField
  • JPasswordField
  • JRadioButton
  • JOptionPane

Además, el contenedor primario es el JFrame que es una subclase de java.awt.Frame. Sin embargo, a diferencia de su superclase esta puede ser cerrada u ocultada. Dentro de este contenedor particular se ubican los componentes como botones, etiquetas, cajas de texto, etc.

JFrame

El siguiente código crea un JFrame sin emplear ningún editor gráfico

package view;

import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class JFrameExample {

    public static void main(String[] args) {
        JFrame ventana = new JFrame("JFrame Demo");
        JPanel panel = new JPanel();
        JLabel label = new JLabel("JLabel");
        JButton button = new JButton();
        button.setText("JButton");

        GroupLayout groupLayout = new GroupLayout(panel);
        groupLayout.setHorizontalGroup(
                groupLayout.createParallelGroup(Alignment.LEADING)
                        .addGroup(groupLayout.createSequentialGroup()
                                .addGap(100)
                                .addGroup(groupLayout.createParallelGroup()
                                        .addComponent(label)
                                        .addComponent(button))
                                .addContainerGap(300, Short.MAX_VALUE))
        );
        groupLayout.setVerticalGroup(
                groupLayout.createParallelGroup(Alignment.LEADING)
                        .addGroup(groupLayout.createSequentialGroup()
                                .addGap(40)
                                .addComponent(label)
                                .addGap(20)
                                .addComponent(button)
                                .addContainerGap(200, Short.MAX_VALUE))
        );
        panel.setLayout(groupLayout);

        ventana.add(panel);
        ventana.setSize(600, 400);
        ventana.setLocationRelativeTo(null);
        ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ventana.setVisible(true);
    }
}

Lo que se requiere es un método "main", luego crear un JFrame en este caso llamado "ventana", es el contenedor principal, luego un JPanel dentro del cual se colocarán los JLabel y JButton. En ese momento aparece un código un poco engorroso de métodos que llaman otros métodos dentro y así sucesivamente. Ese código crea un objeto de tipo GroupLayout y lo inicializa con el parámetro JPanel, luego indica la disposición de los componentes dentro del contenedor JPanel de forma horizontal y vertical creando grupos secuenciales (un componente sigue a otro de derecha a izquierda o de arriba hacia abajo). Dentro de cada uno de ellos se indica como parámetro la alineación y se llaman otros métodos que pueden crear otros grupos como los paralelos o directamente agregar un componente con el método "addComponent". También, se encuentran los métodos "addGap" que indican distancia entre los elementos. Finalmente, se indica el "layout" o disposición al JPanel y se procede a agregar el JPanel al JFrame seguido del tamaño de la ventana, ubicación por defecto en la pantalla del monitos, acción al presionar el botón cerrar y haciéndolo visible.

Etiquetas (JLabel)

Este componente puede ser usado para mostrar texto plano, una imagen o una imagen con un texto. También, puede ser usado para mostrar los resultados de un proceso. Los métodos más empleados son:

  • setText() - Permite colocar un valor textual, puede ser empleado para mostrar un resultado en este componente.
  • setFont() - Permite definir tanto el tipo de fuente como estilo (negrita y/o cursiva) y tamaño de la letra.
  • setIcon() - Permite emplear un ícono o imagen y ser mostrado en pantalla.

Cajas de texto (JTextArea, JTextField y JPasswordField)

Estos componentes son empleados para que el usuario ingrese un valor textual y capturarlo. Los JTextField permiten ingresar una línea de texto, los JPasswordField ingresar un valor pero mostrarlo camuflado y los JTextArea permiten ingresar múltiples líneas de texto. Los métodos más empleados son:

  • setText() - Permite colocar un valor textual, puede ser empleado para mostrar un resultado en este componente.
  • getText() - Permite recuperar el valor que tiene la caja de texto.
  • setFont() - Permite definir tanto el tipo de fuente como estilo (negrita y/o cursiva) y tamaño de la letra.
  • setEnabled() - Permite deshabilitar la escritura, pudiendo usarse para mostrar un resultado al igual que en un JLabel

Botones (JButton, JCheckBox y JRadioButton)

Estos componentes permiten diversas formas gráficas con las que el usuario puede interactuar, los JRadioButton permiten elegir una opción de un grupo de estas, los JCheckBox permiten seleccionar más de una opción de un grupo de estas. Finalmente los JButton se emplean principalmente para ejecutar un evento al presionarlo.

Listas desplegables (JComboBox)

Similar al JRadioButton, permite seleccionar una opción de un grupo de estas, pero sin ocupar espacio en la ventana.

Cuadros de diálogo (JOptionPane)

Permite mostrar un cuadro con un mensaje, un ícono y botones. Un código de ejemplo sería:

JOptionPane.showMessageDialog(null,
     "Mensaje", "Título",
     JOptionPane.WARNING_MESSAGE);

El segundo y tercer parámetro indican el mensaje y el título, estos cuadros se pueden emplear para mostrar mensajes de confirmación, error, advertencia u otros.

Java Swing

Dentro de la forma de interactuar con el computador, se inició este proceso mediante las interfaces de línea de comandos, que tenían sus limitaciones como la de ejecutar una tarea a la vez, mostrando cierta discrepancia con la forma de trabajo del ser humano. Como respuesta aparecen las interfaces gráficas de usuario (GUI) con las llamadas WIMP(clic para conocer más) que implementan el uso de ventanas, menús, punteros e íconos.

En el caso de Java se debe emplear una biblioteca gráfica para el uso de las GUI como:

  • AWT, emplea los componentes gráficos del sistema operativo.
  • SWING, se abstrae del sistema operativo y contiene su propia colección de elementos gráficos.

La biblioteca Swing es parte de Java Foundation Classes (JFC), que es una colección de componentes gráficos para la construcción de aplicaciones de escritorio.

La estructura de esta biblioteca gira en torno a componentes y contenedores. Los contenedores son componentes y al mismo tiempo contienen a otros componentes, esto permite que los eventos pueden ser aplicados en contenedores y/o componentes.

Dependiendo del IDE empleado las paletas para el desarrollo gráfico pueden variar ligeramente y a su vez el código autogenerado.

Paleta de componentes en NetBeans


Paleta de componentes en Eclipse


En ambos se puede apreciar que componentes como los JPanel o Panel, JLabel o Label, JButton o Button y muchos más se repiten con diferente nombre, pero al ser visualizados como código se convierten en objetos cuya clase es derivada del JComponent. Es importante mencionar que los diversos IDE contienen herramientas que permiten construir las interfaces gráficamente y generan todo el código conforme se agregan elementos o realizan cambios. Cada IDE tiene una forma particular de crear el código según el "plug-in" que emplee, por ejemplo en NetBeans no encontrará ningún "import" mientras en Eclipse con su complemento WindowsBuilder se utilizarán todo el tiempo, en NetBeans existen partes del código que no se pueden modificar directamente sino solo a través de la pestaña de diseño, en Eclipse todo el código se puede modificar. Además, las paletas de diseño también tendrán diferente diseño, pero la ejecución del código será la misma.

Arrays

Un array en java es un objeto que contiene de cero a más elementos de un mismo tipo, los elementos que contiene son almacenados en el array y se puede acceder a ellos mediante su numeración que comienza con el número 0.



Arrays unidimensionales y bidimensionales

Los arrays representan matrices, en el caso de los de una dimensión a aquellas matrices tipo columna o fila y los bidimensionales a cualquier matriz de "n" filas por "m" columnas.

En el lenguaje Java estas se pueden definir de la siguiente forma:

        
        //Arrays unidimensionales
        int[] vector; // vector[] es un array de valores tipo int
        
        //Arrays bidimensionales
        int[][] matriz; // matriz[][] es un array de valores tipo int[]
         

Como se aprecia, las matrices son arrays de arrays y para declarar cualquier array se debe colocar primero el tipo de dato que almacenarán sea primitivo o tipo objeto, luego dependiendo de la cantidad de dimensiones los corchetes [ ].



Operaciones con arrays

Para crear un array, se debe inicializar el mismo indicando la cantidad de elementos que contendrá o indicando los elementos que va contener de cualquiera de las siguientes maneras

        
        // Sin valores asignados
        byte[] notas = new byte[5]; 
        //Con valores
        String[] cursos = {"Física", "Cálculo", "Filosofía"};
         

Para ir asignando valores dentro del array se puede emplear estructuras repetitivas o manualmente indicando el nombre del array y entre corchetes la posición (conocida como index). Esta posición siempre comienza con cero y su máximo valor es el tamaño del array menos uno.

        
        //Asignación de valores
        notas[0]=20;
        notas[1]=12;
        notas[2]=10;
        notas[3]=15;
        notas[4]=6;
         

Para modificar un valor se realiza el mismo proceso que al asignar valores con el nuevo contenido.

        
        //Modificar un valor
        cursos[1] = "Matemática"; // Cambia 'Cálculo' por 'Matemática'
         

Para poder recorrer un array se pueden emplear estructuras repetitivas "for" con variables de tipo contador o sin estas conocidos en otros lenguajes como "foreach"

        
        //Imprimiendo en consola
        System.out.println("Contenido de notas[]");
        for (int i = 0; i < notas.length; i++) {
            System.out.println(notas[i]);
        }
        
        System.out.println("\nContenido de Cursos[]");
        for (String curso : cursos) {
            System.out.println(curso);
        }
         

Todos los arrays poseen un campo llamado "length" que devuelve el tamaño de este y puede ser empleado para diversas tareas como el límite del contador en una estructura "for", en el segundo caso al recorrer el array se emplea una variable del mismo tipo que el array con un identificador diferente al array, luego dos puntos y el nombre del array, ya no es necesario indicar dentro la posición como sí en el caso del array recorrido mediante una variable de tipo contador.

El programa completo sería:

package test;

public class Arrays {

    public static void main(String[] args) {
        //Creación e inicialización        
        // Sin valores asignados
        byte[] notas = new byte[5]; 
        //Con valores
        String[] cursos = {"Física", "Cálculo", "Filosofía"};
        
        //Asignación de valores
        notas[0]=20;
        notas[1]=12;
        notas[2]=10;
        notas[3]=15;
        notas[4]=6;
        
        //Modificar un valor
        cursos[1] = "Matemática"; // Cambia 'Cálculo' por 'Matemática'
        
        //Imprimiendo en consola
        System.out.println("Contenido de notas[]");
        for (int i = 0; i < notas.length; i++) {
            System.out.println(notas[i]);
        }
        
        System.out.println("\nContenido de cursos[]");
        for (String curso : cursos) {
            System.out.println(curso);
        }
    }
}

Se obtiene un resultado como el siguiente:

Contenido de notas[]
20
12
10
15
6

Contenido de cursos[]
Física
Matemática
Filosofía

martes, 20 de octubre de 2020

Estructuras repetitivas

Las estructuras repetitivas permiten ejecutar bloques de sentencias múltiples veces, aun si no conocemos el número de veces que debe repetirse el código. Se puede usar para ello una determinada condición, de manera que el bloque se detendrá cuando no se cumpla la condición.

Ejemplo práctico: al ingresar productos en una factura, el proceso se repite una y otra vez.

Estructura FOR

Se emplea cuando se conoce la cantidad de repeticiones o al recorrer un arreglo o vector.

for ( [tipo numérico] i = [valor inicial]; i <= [valor máximo]; [aumento o decremento] ) {
   //Sentencias que se van a repetir: "(valor máximo - valor inicial)" veces
}


for ( [tipo igual al arreglo] i in [variable tipo arreglo] ) {
   //Sentencias que se van a repetir tantas veces como elementos tenga
   //el arreglo
} 


Estructura WHILE y DO WHILE

Se emplea cuando el número de repeticiones no es conocido, pues depende de una condición. El punto a analizar es si se debe o no ejecutar la iteración por lo menos una vez.

while ( condición ) {
   //Sentencias que se van a repetir mientras condición sea verdadera
}

do {
   //Sentencias que se van a repetir por lo menos una vez y mientras condición sea verdadera
}while ( condición ); 


Ejemplo en código

El siguiente programa muestra todos los números pares entre dos valores ingresados por el usuario, validando que sean positivos y el segundo valor sea mayor que el primero

package test;

import java.util.Scanner;

public class Repetitivos {

    public static void main(String[] args) {
        Scanner scanner;
        int n1, n2;
        scanner = new Scanner(System.in);
        
        do {
            System.out.print("Ingrese un número positivo: ");
            n1 = scanner.nextInt();
        } while (n1 <= 0);

        do {
            System.out.print("Ingrese un número mayor que " + n1 + ": ");
            n2 = scanner.nextInt();
        } while (n2 <= n1);

        for (int i = n1; i <= n2; i++) {
            if (i % 2 == 0) {
                System.out.print(i + " ");
            }
        }
    }
}

Estructuras condicionales

Las estructuras condicionales permiten ejecutar bloques de sentencias de código para una determinada condición, si esta no se cumple se puede optar por no realizar nada o llevar a cabo otro bloque de sentencias, de manera que no pueden ejecutarse ambos bloques, solo uno de ellos.

Ejemplo práctico: al ingresar nuestra contraseña de una red social, si es incorrecta no podemos ingresar, pero si es correcta ingresamos a nuestra cuenta.


Condicional IF ELSE Condicional SWITCH CASE
if (condicion1) {
   //Sentencias si 
   //Condicion1 es verdad
}else if (condicion2) {
   //Sentencias si 
   //Condicion2 es verdad
}else {
   //Sentencias si condicion1 y
   //condicion2 no son verdad
}
switch (expresión) {
case x :
   //Sentencias si expresión es "x"
   break;
case y :
   //Sentencias si expresión es "y"
   break;
default:
   //Sentencias para otros casos
}


Operador ternario

Cuando tenemos una estructura condicional simple no anidada y sin "else if", lo más óptimo es utilizar un operador ternario, hay que tener en cuenta que no debe ser usado a diestra y siniestra, solo en casos donde exista un retorno de valor.

Condicional if-else Condicional con operador ternario
/*Codicional clásico*/
if (condicion) {
   //Sentencias si 
   //Condicion es verdad
}else {
   //Sentencias si condicion
   //no son verdad
}
/*Codicional clásico*/
[variable u otro] (condicion) ?
   //Sentencias si 
   //Condicion es verdad
:
   //Sentencias si condicion
   //no son verdad 
;  // cerrar la sentencia al final


Código de ejemplo

El siguiente código solicita la nota de un estudiante y de acuerdo a esta muestra un mensaje. Primero valida que la nota este en el rango de 0 a 20, luego si es 10 o menor muestra el mensaje "Desaprobado", si es 15 o menor muestra "Requiere recuperación" y en los demás muestra "Aprobado"

package test;

import java.util.Scanner;

public class Condicional {

    public static void main(String[] args) {
        Scanner scanner;
        byte nota;

        System.out.print("Ingrese la nota del estudiante: ");
        scanner = new Scanner(System.in);
        nota = scanner.nextByte();
        if (nota < 0 || nota > 20) {
            System.out.println("Nota inválida");
        } else if (nota <= 10) {
            System.out.println("Desaprobado");
        } else if (nota <= 15) {
            System.out.println("Requiere recuperación");
        } else {
            System.out.println("Aprobado");
        }
    }
}

El siguiente código solicita un número entre 1 y 7 devolviendo el día correspondiente iniciando la semana en el lunes

package test;

import java.util.Scanner;

public class Tipos {

    public static void main(String[] args) {
        Scanner scanner;
        byte dia;

        System.out.print("Ingrese un número del 1 al 7: ");
        scanner = new Scanner(System.in);
        dia = scanner.nextByte();
        switch (dia){
            case 1: System.out.println("LUNES");break;
            case 2: System.out.println("MARTES");break;
            case 3: System.out.println("MIERCOLES");break;
            case 4: System.out.println("JUEVES");break;
            case 5: System.out.println("VIERNES");break;
            case 6: System.out.println("SABADO");break;
            case 7: System.out.println("DOMINGO");break;
            default: System.out.println("Valor inválido");break;
        }    
    }
}

Tipos de datos

Datos primitivos

Java admite ocho tipos de datos básicos conocidos como tipos primitivos. Además, admite clases y matrices como tipos de datos compuestos o tipos de referencia.

Los tipos primitivos son:

  • boolean
  • byte
  • short
  • int
  • float
  • double
  • long
  • char

En la siguiente tabla se aprecia las características de estos

Tipo Contenido Rango Tamaño
byte Valor numérico entero -128 a 127 8 bits
short Valor numérico entero –32768 a 32767 16 bits
int Valor numérico entero –2147483648 a 2147483647 32 bits
long Valor numérico entero –9223372036854775808 a 9223372036854775807 64 bits
float Valor numérico con decimales ±1.4E–45 a ±3.4028235E+38 32 bits
double Valor numérico con decimales ±4.9E–324 a ±1.7976931348623157E+308 64 bits
boolean Valor lógico "false" y "true" 1 bit
char Caracter UNICODE \u0000 - \uFFFF 16 bits

Podemos ver en el siguiente código como crear variables de estos tipos y asignarles un contenido.

package test;

public class Tipos {

    public static void main(String[] args) {
        /*DECLARANDO VARIABLES*/

        //Variable lógica
        boolean log;
        
        //Variables enteras
        byte ent1;
        short ent2;
        int ent3;
        long ent4;
        
        //Variables con decimal
        float dec1;
        double dec2;
        
        //Variable caracter
        char caracter;
        
        /*ASIGNANDO VALORES*/
        log = true;
        ent1 = -100;
        ent2 = 4000;
        ent3 = -120000;
        ent4 = 490000000;
        dec1 = 1e7f;
        dec2 = 3.14d;
        caracter = '\u0026';
        
        /*MOSTRANDO EL CONTENIDO*/
        System.out.print("log = ");
        System.out.println(log);
        System.out.print("ent1 = ");
        System.out.println(ent1);
        System.out.print("ent2 = ");
        System.out.println(ent2);
        System.out.print("ent3 = ");
        System.out.println(ent3);
        System.out.print("ent4 = ");
        System.out.println(ent4);
        System.out.print("dec1 = ");
        System.out.println(dec1);
        System.out.print("dec2 = ");
        System.out.println(dec2);
        System.out.print("caracter = ");
        System.out.println(caracter);
    }    
}

Podemos ver en el siguiente código como crear variables de estos tipos y asignarles un contenido.

log = true
ent1 = -100
ent2 = 4000
ent3 = -120000
ent4 = 490000000
dec1 = 1.0E7
dec2 = 3.14
caracter = &