Mostrar Mensajes

Esta sección te permite ver todos los posts escritos por este usuario. Ten en cuenta que sólo puedes ver los posts escritos en zonas a las que tienes acceso en este momento.


Mensajes - Kabuto

Páginas: 1 ... 14 15 16 17 18 [19] 20 21 22 23 24 ... 50
361
Comunidad / Re: Presentación
« en: 16 de Agosto 2021, 12:09 »
Hola y bienvenido.
Espero que te encuentres a gusto por aquí y participes activamente.

Un saludo.

362
El resultado en pantalla sería:
Citar
a b c

¿Por qué?

El método main hace una instancia de la Clase3

Código: [Seleccionar]
    public static void main(String args[]) {
        new Clase3();
    }
Esta clase, en su constructor imprime una "c " en pantalla.
Pero como hereda de Clase2, antes de ejecutar el código de su constructor, ejecuta el constructor de su madre Clase2, que imprime una "b " en pantalla.

Pero resulta que Clase2, hereda de Clase, así que antes de ejecutar su constructor, ejecuta el del Clase, que imprime una "a " en pantalla.

La conclusión es que una clase que hereda de otra, cuando se hace una instancia de ella, lo primero que hace es "construir" a su clase madre, quien si a su vez también hereda de otra clase, construirá primero a esta.

Entonces, al construir un objeto Clase3, previamente se hace la construcción de Clase2, quién previamente construye Clase.

Así Clase3, es el resultado de los constructores que hayan en la línea de herencia.


Se podría comprobar con este código:

Código: [Seleccionar]
public class Main
{
    public static class Clase {
        public Clase() {
            System.out.print("a ");
        }
    }

    public static class Clase2  extends Clase {
        public Clase2() {
            System.out.print("b ");
        }
    }

    public static class Clase3 extends Clase2 {
        public Clase3() {
            System.out.print("c ");
        }
    }

    public static void main(String args[]) {
        new Clase3();
    }
}

363
No me llevo muy bien con las pilas y las colas....

En cualquier caso, aquí no veo que se estén buscando números primos:
Código: [Seleccionar]
if(aux.peek()%2==0||aux.peek()==1){
                push(aux.peek());
                aux.pop();
                if(aux.isEmpty()){
                    break;
                }
            }else{
                aux.pop();
                if(aux.isEmpty()){
                    break;
                }

Con ese if else, se está distinguiendo entre pares e impares, pero no primos.
Que NINGÚN número par es primo.
Pero no todos los impares son primos.

Necesitarías un método de apoyo, que sea tipo boolean, de manera que reciba un entero y diga TRUE si es primo o FALSE si no lo es.

Un número primo es aquel que solo es divisible por sí mismo (bueno, y por 1, porque todos los números son divisibles por 1)
Por ejemplo si el método recibe el número 9, pues ha de comprobar si es divisible por 8, por 7, por 6, por 5, por 4, por 3 ó por 2.
Si es divisible por alguno de ellos, entonces NO es primo.

Resulta que 9 SÍ es divisible por 3,
Citar
9 % 3 == 0 es TRUE
Por tanto, 9 NO es primo.

Para desarrollar un algoritmo que compruebe lo de ser primo, ya habrás deducido que se necesita un bucle que vaya en orden inverso comenzando por n-1 hasta llegar a 2.
Y en cada iteración comprobar si n es divisible por alguno de los números de esa secuencia.

Intenta escribir ese algoritmo, o busca ejemplos por la red, que los habrá a montones.

364

para la 6 como puedo retornar la cantidad de alojamientos que se han registrado???
Basta con preguntar cuánto mide el ArrayList donde se guardan los alojamientos.

A la clase Turismo le añades este métod:
Código: [Seleccionar]
public int alojamientosRegistrados() {
return empresaTurismo.size();
}


para el punto 8  esta el siguiente metodo:
incrementaValorBase: aumenta el valor base en un 18% si la capacidad de la cabaña es superior a 5. como puedo identicar si un objeto guardado es de tipo cabaña para poder aplicar el incremento????

tengo el siguiente metodo para eso:
public int incrementaValorBase(){
        int valorbase=0;
        if (this.capacidad >5){
            valorbase = this.valorBaseNoche + Math.round(this.valorBaseNoche*18/100);
            return valorbase;
        }else{
            System.out.println("no aplica incremento ya que su capacidad es menor a 5");
        }
        return valorbase;
    }

¿Solo se aplica a Cabagna o a las dos Hospedería (Cabagna y Hotel)

Si solo es Cabagna, pues a su clase le podemos añadir este método:
Código: [Seleccionar]
public void incrementaValorBase() {
if (capacidad <= 5)
System.out.println("no aplica incremento ya que su capacidad es menor a 5");
else {
System.out.printf("Valor base actual: %.2f\n", valorBaseNoche);
valorBaseNoche += 18*valorBaseNoche/100;
System.out.printf("Valor base tras incremento: %.2f\n", valorBaseNoche);
}
}
Y si fuera también para Hotel, entonces se podría añadir tal cuál a la clase Hospederia y así ambas lo heredan.

Este método no tiene por qué retornar nada, solo alterar el valor de su atributo, pero sí haremos que informe en pantalla para poder comprobar su funcionamiento.

Luego, a la clase Turismo, que es quien gestiona los medios de alojamiento, le añadimos el siguiente método que lo que hace es recorrer todos los medios de alojamiento y preguntar por cada uno si es una Cabagna o no.
Si es una Cabagna, lo instanciamos como tal para poder acceder al método anterior (en el ArrayList está instanciado como MedioAlojamiento y por tanto ese método no sería visible) y una vez instanciado le pedimos que incremente el valor base.

De nuevo mostraremos mensajes en pantalla complementarios para poder ver en pantalla qué está ocurriendo internamente.

Código: [Seleccionar]
public void incrementarValoresBase() {
for (int i = 0; i < empresaTurismo.size(); i++) {
if (empresaTurismo.get(i) instanceof Cabagna) { //Preguntamos si este alojamiento es una Cabaña
//Sí lo es, lo instanciamos como Cabaña
Cabagna cab = (Cabagna) empresaTurismo.get(i);
//Le ordenamos que aumente su valor base, si le corresponde
System.out.println("\nAlojamiento #" + i + " es una Cabaña...");
cab.incrementaValorBase();
}
}
}

Ya por último, en la clase App, cuando el usuario solicite esa acción de incrementar los valores base, solo hay que pedirle al objeto Turismo que lo haga.
En mi programa, que tengo menos opciones, sería la opción nº 4

Citar
   public static void main(String[] args) {
      int opcion = 0;

      do {
         opcion = menu();
         switch(opcion) {
         case 0:
            System.out.println("\nFIN DE PROGRAMA");
            break;
         case 1:
            ingresarMedio();
            break;
         case 2:
            turismo.muestraTodo();
            break;
         case 3:
            System.out.println("\nCONSULTAR CLIENTE\n");
            System.out.print("RUT: ");
            String rut = teclado.nextLine();
            turismo.datosUnCliente(rut);
            break;
         case 4:
            turismo.incrementarValoresBase();
            break;

         default:
            System.out.println("\nOpción incorrecta");
         }
      }while (opcion != 0);
   }

Y al elegir esa opción, en pantalla veremos que efectivamente el programa busca Cabagnas e incrementa el valor base si corresponde.
Si lo ejecutamos varias veces seguidas, veremos que el incremento no es un resultado que se calcula y se devuelve, si no que el atributo "valor base noche" queda modificado tras cada ejecución.

Citar
Empresa Turismo
-----------------------
1) Ingresar Medio de Alojamiento
2) Mostrar medios de alojamiento
3) Datos de un cliente
4) Incrementar valor base noche de las Cabañas
0) SALIR
-----------------------
Favor ingrese una opción....
4

Alojamiento #0 es una Cabaña...
Valor base actual: 100,00
Valor base tras incremento: 118,00

Alojamiento #2 es una Cabaña...
No aplica incremento ya que su capacidad es menor a 5

Alojamiento #4 es una Cabaña...
Valor base actual: 98,50
Valor base tras incremento: 116,23


Empresa Turismo
-----------------------
1) Ingresar Medio de Alojamiento
2) Mostrar medios de alojamiento
3) Datos de un cliente
4) Incrementar valor base noche de las Cabañas
0) SALIR
-----------------------
Favor ingrese una opción....
4

Alojamiento #0 es una Cabaña...
Valor base actual: 118,00
Valor base tras incremento: 139,24

Alojamiento #2 es una Cabaña...
No aplica incremento ya que su capacidad es menor a 5

Alojamiento #4 es una Cabaña...
Valor base actual: 116,23
Valor base tras incremento: 137,15


Empresa Turismo
-----------------------
1) Ingresar Medio de Alojamiento
2) Mostrar medios de alojamiento
3) Datos de un cliente
4) Incrementar valor base noche de las Cabañas
0) SALIR
-----------------------
Favor ingrese una opción....
0

FIN DE PROGRAMA

365
Como lo de preguntar si o no se hace más de una vez, puedes crear un método específico.

Un método que consista en un bucle que solo termine cuando se nos da una de las dos respuestas deseadas, y además termine retornando TRUE si respondió "si" o FALSE si respondió "no".

Te dejo un ejemplo:

Código: [Seleccionar]
public class Main
{
   
    private static Scanner teclado = new Scanner(System.in);
   
    public static void main(String[] args) {
        System.out.println("Responda Si o NO");
        boolean siOno = pedirSiNo();
       
        System.out.println("Ha respondido que " + (siOno?"SI":"NO"));
    }
   
    private static boolean pedirSiNo() {
        while(true) {
            String respuesta = teclado.nextLine();
            switch (respuesta.toLowerCase()) {
                case "si":
                    return true;
                case "no":
                    return false;
            }
        }
    }
}

Si ejecutamos este programa, veremos que sigue pidiendo el dato hasta que se responde SI o NO:

Citar
Responda Si o NO
hola
adios
s
n
no
Ha respondido que NO


Si quisieras que cada vez que repite la petición del dato, muestre de nuevo cuál era la pregunta, puedes modificar el método para que reciba como argumento el String con la pregunta que ha de mostrarse:
Código: [Seleccionar]
public class Main
{
   
    private static Scanner teclado = new Scanner(System.in);
   
    public static void main(String[] args) {
        boolean siOno = pedirSiNo("Responda Si o NO");
       
        System.out.println("Ha respondido que " + (siOno?"SI":"NO"));
    }
   
    private static boolean pedirSiNo(String pregunta) {
        while(true) {
            System.out.println(pregunta);
            String respuesta = teclado.nextLine();
            switch (respuesta.toLowerCase()) {
                case "si":
                    return true;
                case "no":
                    return false;
            }
        }
    }
}

Citar
Responda Si o NO
hola
Responda Si o NO
bye
Responda Si o NO
n
Responda Si o NO
SIIIIIIII
Responda Si o NO
si
Ha respondido que SI

366
Hola.

Por eso yo en las clases que escribí les puse un método toString(), porque así de forma sencilla podemos mostrar todos los datos, tanto del cliente como del alojamiento que ha registrado.

Mira, te dejo mi versión de la clase Turismo.
Fíjate que para agregar un alojamiento, uso el método contains() para saber si este cliente ya tiene registrado un alojamiento de ese mismo tipo, y por tanto se rechazaría el registro.
contains() funciona como quiero porque a las clases les puse a cada una un método equals(), y el ArrayList se vale de estos equals() para comprobar si ya contiene un objeto equivalente/igual al que queremos agregar.

Según entendí el enunciado, un cliente solo puede tener registrado un alojamiento de cada tipo. Por tanto, un mismo cliente puede tener registrado un Hotel, una Cabaña y una Carpa.

Para el método de mostrar todo, fíjate que solo necesito unas pocas líneas, esto es porque a las clases ya les puse un método toString() para mostrar toda la info.

Y el método para mostrar datos de un cliente, recorre el ArrayList y cada vez que encuentra un RUT coincidente, muestra todos los datos del alojamiento, lo cuál incluye los datos del Cliente.

Si este Cliente tiene varios alojamientos registrados (recordemos que puede tener uno de cada tipo), se mostrarán todos en pantalla.

Código: [Seleccionar]
public class Turismo {

private ArrayList<MedioDeAlojamiento> empresaTurismo;

public Turismo() {
empresaTurismo = new ArrayList<MedioDeAlojamiento>();
}

public void agregarAlojamiento(MedioDeAlojamiento alojamiento) {
if (empresaTurismo.contains(alojamiento)) {
System.out.println("\nEste Cliente ya tiene registrado un alojamiento de este tipo.");
System.out.println("No puede registrarse otro más.");
}
else
empresaTurismo.add(alojamiento);
}

public void muestraTodo() {
System.out.println("\nALOJAMIENTOS REGISTRADOS");
System.out.println("------------ -----------\n");
for (MedioDeAlojamiento alojamiento: empresaTurismo)
System.out.println(alojamiento);
}

public void datosUnCliente(String rut) {
boolean encontrado = false;

for (int i = 0; i < empresaTurismo.size(); i++)
if (empresaTurismo.get(i).getCliente().getRut().equalsIgnoreCase(rut)) {
System.out.println(empresaTurismo.get(i)); //Aquí se invoca el toString() del alojamiento, que muestra toda la info
encontrado = true;
}

if (!encontrado)
System.out.println("No hay datos registrados para este cliente");
}

}


Y ahora la clase App.
Es similar a la tuya, con pequeños cambios, a parte de que solo he puesto las tres opciones que indicaba el enunciado que pusiste antes.

Código: [Seleccionar]
public class App {

private static Turismo turismo = new Turismo();
private static Scanner teclado = new Scanner(System.in);

public static void main(String[] args) {
int opcion = 0;

do {
opcion = menu();
switch(opcion) {
case 0:
System.out.println("\nFIN DE PROGRAMA");
break;
case 1:
ingresarMedio();
break;
case 2:
turismo.muestraTodo();
break;
case 3:
System.out.println("\nCONSULTAR CLIENTE\n");
System.out.print("RUT: ");
String rut = teclado.nextLine();
turismo.datosUnCliente(rut);
break;
default:
System.out.println("\nOpción incorrecta");
}
}while (opcion != 0);
}

private static int menu(){
        System.out.println("\nEmpresa Turismo");
        System.out.println("-----------------------");
        System.out.println("1) Ingresar Medio de Alojamiento");
        System.out.println("2) Mostrar medios de alojamiento");
        System.out.println("3) Datos de un cliente");
        System.out.println("0) SALIR");
        System.out.println("-----------------------");
        System.out.println("Favor ingrese una opción....");
        return Integer.parseInt(teclado.nextLine());
}

private static void ingresarMedio() {

MedioDeAlojamiento alojamiento = null;
DatosCliente cliente = crearCliente();

int ingreso;
        do {
            System.out.println("Favor indique Hospederia...");
            System.out.println("1) Carpa");
            System.out.println("2) Hotel");
            System.out.println("3) Cabaña");
            ingreso= Integer.parseInt(teclado.nextLine());
        }while(ingreso<1 || ingreso>3);
       
       
        switch(ingreso) {
        case 1:
        alojamiento = crearCarpa(cliente);
        break;
        case 2:
        alojamiento = crearHotel(cliente);
        break;
        case 3:
        alojamiento = crearCabagna(cliente);
        }
       
        turismo.agregarAlojamiento(alojamiento);

}

private static DatosCliente crearCliente() {
System.out.println("DATOS CLIENTE\n");
System.out.print("RUT: ");
String rut = teclado.nextLine();
System.out.print("Nombre: ");
String nombre = teclado.nextLine();
return new DatosCliente(rut, nombre);
}

private static Carpa crearCarpa(DatosCliente cliente) {
System.out.print("Cantidad de Noches: ");
int cantNoches = Integer.parseInt(teclado.nextLine());

        System.out.print("Valor Base Noche: ");
        float baseNoche = Float.parseFloat(teclado.nextLine());
       
        String temporada;
        do{
            System.out.println("¿Temporada alta, media o baja?");
            temporada = teclado.nextLine();
        }while(temporada.compareToIgnoreCase("alta")!=0
                && temporada.compareToIgnoreCase("media")!=0
                && temporada.compareToIgnoreCase("baja")!=0);
       
        System.out.print("Cantidad de Personas: ");
int cantPersonas = Integer.parseInt(teclado.nextLine());

return new Carpa(cliente, baseNoche, temporada, cantNoches, cantPersonas);
}

private static Hotel crearHotel(DatosCliente cliente) {
System.out.print("Cantidad de Noches: ");
int cantNoches = Integer.parseInt(teclado.nextLine());

        System.out.print("Valor Base Noche: ");
        float baseNoche = Float.parseFloat(teclado.nextLine());
       
        String temporada;
        do{
            System.out.println("¿Temporada alta, media o baja?");
            temporada = teclado.nextLine();
        }while(temporada.compareToIgnoreCase("alta")!=0
                && temporada.compareToIgnoreCase("media")!=0
                && temporada.compareToIgnoreCase("baja")!=0);
       
        System.out.print("Capacidad: ");
        int capacidad = Integer.parseInt(teclado.nextLine());
       
        System.out.print("Fumador (si/no): ");
        boolean esFumador = teclado.nextLine().equalsIgnoreCase("si");
       
        System.out.print("Con Desayuno (si/no): ");
        boolean conDesayuno = teclado.nextLine().equalsIgnoreCase("si");
       
        return new Hotel(cliente, baseNoche, temporada, cantNoches, capacidad, esFumador, conDesayuno);
}

private static Cabagna crearCabagna(DatosCliente cliente) {
System.out.print("Cantidad de Noches: ");
int cantNoches = Integer.parseInt(teclado.nextLine());

        System.out.print("Valor Base Noche: ");
        float baseNoche = Float.parseFloat(teclado.nextLine());
       
        String temporada;
        do{
            System.out.println("¿Temporada alta, media o baja?");
            temporada = teclado.nextLine();
        }while(temporada.compareToIgnoreCase("alta")!=0
                && temporada.compareToIgnoreCase("media")!=0
                && temporada.compareToIgnoreCase("baja")!=0);
       
        System.out.print("Capacidad: ");
        int capacidad = Integer.parseInt(teclado.nextLine());
       
        System.out.print("Fumador (si/no): ");
        boolean esFumador = teclado.nextLine().equalsIgnoreCase("si");
       
        System.out.print("Con Chimenea (si/no): ");
        boolean conChimenea = teclado.nextLine().equalsIgnoreCase("si");
       
        return new Cabagna(cliente, baseNoche, temporada, cantNoches, capacidad, esFumador, conChimenea);
}

}

367
Yo creo entender que se han de pedir TODOS los datos al usuario, es decir, no vamos a tener Cabañas, Carpas, Hoteles... predefinidas para ir asignando a los clientes.

El proceso sería:
- Pedir datos Cliente
- Preguntar si quiere Carpa, Cabaña u Hotel...
- Pedir los datos adecuados al alojamiento escogido
- Añadirlo a la colección, controlando que este Cliente no tenga ya previamente asociado ese mismo MedioDeAlojamiento.


Lo que si puede ser un poco confuso son las relaciones entre clases.
Viendo el diagrama, yo las interpreto así:

Clase DatosCliente
Código: [Seleccionar]
public class DatosCliente {

private String rut;
private String nombre;

public DatosCliente(String rut, String nombre) {
this.rut = rut;
this.nombre = nombre;
}

public String getRut() {
return rut;
}

public void setRut(String rut) {
this.rut = rut;
}

public String getNombre() {
return nombre;
}

public void setNombre(String nombre) {
this.nombre = nombre;
}

@Override
public String toString() {
return String.format("RUT: %s -- Nombre: %s", rut, nombre);
}

}

A continuación, la superclase MedioDeAlojamiento.
Esta clase tiene los atributos que son comunes a todos los medios de alojamiento.
La podemos declarar como abstracta porque en principio no nos interesa que se puedan crear objetos directamente de esta clase. Esta clase está destinada a iniciar unas relaciones de herencia, no a funcionar como una entidad individual.

Código: [Seleccionar]
public abstract class MedioDeAlojamiento {

protected DatosCliente cliente;
protected float valorBaseNoche;
protected String tipoTemporada;
protected int cantidadNoches;

public MedioDeAlojamiento(DatosCliente cliente, float valorBaseNoche, String tipoTemporada, int cantidadNoches) {
this.cliente = cliente;
this.valorBaseNoche = valorBaseNoche;
this.tipoTemporada = tipoTemporada;
this.cantidadNoches = cantidadNoches;
}

public DatosCliente getCliente() {
return cliente;
}

public void setCliente(DatosCliente cliente) {
this.cliente = cliente;
}

public float getValorBaseNoche() {
return valorBaseNoche;
}

public void setValorBaseNoche(float valorBaseNoche) {
this.valorBaseNoche = valorBaseNoche;
}

public String getTipoTemporada() {
return tipoTemporada;
}

public void setTipoTemporada(String tipoTemporada) {
this.tipoTemporada = tipoTemporada;
}

public int getCantidadNoches() {
return cantidadNoches;
}

public void setCantidadNoches(int cantidadNoches) {
this.cantidadNoches = cantidadNoches;
}

}

La clase Carpa es hija directa de MedioDeAlojamiento, así que hereda de esta y añade el atributo cantidadPersonas que es propio de Carpa.
Además añade un método equals() para establecer la regla de que dos Carpa son iguales/equivalentes si tienen asociado el mismo cliente.
También un método toString() para mostrar toda la información relativa a esta Carpa

Código: [Seleccionar]
public class Carpa extends MedioDeAlojamiento {

private int cantidadPersonas;

public Carpa(DatosCliente cliente, float valorBaseNoche, String tipoTemporada,
int cantidadNoches, int cantidadPersonas) {
super(cliente, valorBaseNoche, tipoTemporada, cantidadNoches);
this.cantidadPersonas = cantidadPersonas;
}

public int getCantidadPersonas() {
return cantidadPersonas;
}

public void setCantidadPersonas(int cantidadPersonas) {
this.cantidadPersonas = cantidadPersonas;
}

@Override
public String toString() {
StringBuilder cadena = new StringBuilder();
cadena.append("\n\t*** Cliente alojado ***\n" + cliente);
cadena.append("\n\t*** Datos Alojamiento ***\n");
cadena.append("Tipo Alojamiento: Carpa\n");
cadena.append(String.format("Valor Noche: %.2f -- Temporada: %s\n",
valorBaseNoche, tipoTemporada));
cadena.append(String.format("Cantidad Noches: %d -- CantidadPersonas: %d",
cantidadNoches, cantidadPersonas));

return cadena.toString();
}

@Override
public boolean equals(Object objeto) {
/*
* Dos Carpa se consideran "equivalentes
* si tienen asociado el mismo cliente.
*/
if (objeto instanceof Carpa) {
Carpa otraCarpa = (Carpa) objeto;
return cliente.getRut().equals(otraCarpa.getCliente().getRut());
}
else
return false;
}

}

Quedan dos clases, Cabagna y Hotel, pero no son hijas directas de MedioDeAlojamiento.
Hay una clase intermedia llamada Hospederia, con los atributos comunes a estas dos últimas clases.
También la podemos declarar abstracta.

Código: [Seleccionar]
public abstract class Hospederia extends MedioDeAlojamiento {

protected int capacidad;
protected boolean esFumador;

public Hospederia(DatosCliente cliente, float valorBaseNoche, String tipoTemporada,
int cantidadNoches, int capacidad, boolean esFumador) {
super(cliente, valorBaseNoche, tipoTemporada, cantidadNoches);
this.capacidad = capacidad;
this.esFumador = esFumador;
}

}

Ahora sí, las dos últimas clases.
Cabagna agrega el atributo chimenea y posee métodos toString() y equals() apropiados para ella:
Código: [Seleccionar]
public class Cabagna extends Hospederia {

private boolean chimenea;

public Cabagna(DatosCliente cliente, float valorBaseNoche, String tipoTemporada,
int cantidadNoches, int capacidad, boolean esFumador, boolean chimenea) {
super(cliente, valorBaseNoche, tipoTemporada, cantidadNoches, capacidad, esFumador);
this.chimenea = chimenea;
}

public boolean conChimenea() {
return chimenea;
}


public void setChimenea(boolean chimenea) {
this.chimenea = chimenea;
}

@Override
public String toString() {
StringBuilder cadena = new StringBuilder();
cadena.append("\n\t*** Cliente alojado ***\n" + cliente);
cadena.append("\n\t*** Datos Alojamiento ***\n");
cadena.append("Tipo Alojamiento: Cabaña\n");
cadena.append(String.format("Valor Noche: %.2f -- Temporada: %s\n",
valorBaseNoche, tipoTemporada));
cadena.append(String.format("Cantidad Noches: %d -- Capacidad: %d\n", cantidadNoches ,capacidad));
cadena.append(String.format("Fumador: %s -- Chimenea: %s",
esFumador?"SI":"NO", chimenea?"SI":"NO"));

return cadena.toString();
}

@Override
public boolean equals(Object objeto) {
/*
* Dos Cabagna se consideran "equivalentes
* si tienen asociado el mismo cliente.
*/
if (objeto instanceof Cabagna) {
Cabagna otraCabagna = (Cabagna) objeto;
return cliente.getRut().equals(otraCabagna.getCliente().getRut());
}
else
return false;
}

}

Y Hotel, lo mismo, agregando el atributo desayuno:
Código: [Seleccionar]
public class Hotel extends Hospederia {

private boolean conDesayuno;

public Hotel(DatosCliente cliente, float valorBaseNoche, String tipoTemporada, int cantidadNoches, int capacidad,
boolean esFumador, boolean conDesayuno) {
super(cliente, valorBaseNoche, tipoTemporada, cantidadNoches, capacidad, esFumador);
this.conDesayuno = conDesayuno;
}

public boolean conDesayuno() {
return conDesayuno;
}



public void setConDesayuno(boolean conDesayuno) {
this.conDesayuno = conDesayuno;
}


@Override
public String toString() {
StringBuilder cadena = new StringBuilder();
cadena.append("\n\t*** Cliente alojado ***\n" + cliente);
cadena.append("\n\t*** Datos Alojamiento ***\n");
cadena.append("Tipo Alojamiento: Hotel\n");
cadena.append(String.format("Valor Noche: %.2f -- Temporada: %s\n",
valorBaseNoche, tipoTemporada));
cadena.append(String.format("Cantidad Noches: %d -- Capacidad: %d\n", cantidadNoches ,capacidad));
cadena.append(String.format("Fumador: %s -- Desayuno: %s",
esFumador?"SI":"NO", conDesayuno?"SI":"NO"));

return cadena.toString();
}

@Override
public boolean equals(Object objeto) {
/*
* Dos Hotel se consideran "equivalentes
* si tienen asociado el mismo cliente.
*/
if (objeto instanceof Hotel) {
Hotel otroHotel = (Hotel) objeto;
return cliente.getRut().equals(otroHotel.getCliente().getRut());
}
else
return false;
}
}


Con estas clases, se haría un programa con alguna colección, por ejemplo un ArrayList<MedioDeAlojamiento> alojamientos; y habría que ir pidiendo todos los datos necesarios para registrar clientes y alojamientos.

Inténtalo.
Yo luego cuanto tenga tiempo, miraré de hacer mi propia versión.

Un saludo.

368
Hola.

Para hacer que se repita la petición hasta que el usuario introduzca un valor dentro del rango admitido, sí, hay que usar while.
Pero hay que poner una condición de repetición que sea lógica.

Tu has puesto una variable "contador" que mientras sea menor que 1, se repita.
Eso puede funcionar, siempre y cuando luego modifiques el valor de "contador" para evitar que el bucle sea infinito.

Pero no es "lógico", porque no estamos contando nada.
Imagina que otra persona lee tu código, sin tener el enunciado así que no sabe cuáles son las condiciones impuestas al programa.

Si ve una variable "contadora", y ve que el valor de ese contador influye en la condición del bucle... pensará que este programa debería estar "contando" algo, pero no es así.
¿Entiendes lo que quiero decir?

Nuestros programas han de ser lo más entendible posible para otras personas, e incluso para ti.
Porque a lo mejor dentro de 6 meses, que quizás ya has olvidado este ejercicio, te encuentras con este código... y tu mismo puedes quedarte confuso y preguntándote por qué pusiste un contador como condición del bucle... si no se está contando nada.


Para lograr que el programa sea entendible, hay que intentar transmitir al código el mismo proceso mental que hacemos en nuestra cabeza.

Es decir, la lógica que seguimos en la cabeza es:

Citar
* Pido una nota
* ¿Está FUERA del rango admitido?
    - SÍ/TRUE: Pues vuelvo a pedirla sin computar nada
    - NO/FALSE: Pues dejo de pedirla y la computo

De ahí podemos deducir cuál sería la condición idónea para el bucle WHILE: que se repita mientras nota fuera de rango sea cierto (true)

Esto lo podemos representar con una variable boolean y dándole el nombre adecuado.

Código: [Seleccionar]
public class Calificaciones {

public static void main(String[] args) {

float calificacion = 0;
boolean fueraDeRango = true;

while(fueraDeRango){ //Mientras la nota esté fuera de rango, se repetirá el bucle

calificacion=Float.parseFloat(JOptionPane.showInputDialog("Ingresar Nota"));

if (calificacion > 10 || calificacion < 0)
JOptionPane.showMessageDialog(null, "Introduzca una calificación valida entre 0 y 10 ");
else {
fueraDeRango = false; //La nota es valida, está DENTRO de rango, ya no se repetirá el bucle
if(calificacion <= 7)
JOptionPane.showMessageDialog(null, "Esta Reprobado");
else
JOptionPane.showMessageDialog(null, "Esta Aprobado");
}
}
}
}

¿Ves? Ahí no estamos usando ningún "contador" que pueda llevar a confusión.
Solo con leerlo ya se adivina la lógica que sigue el programa.

Por cierto, ahí también se ve como controlar correctamente si está dentro del rango o no.
De nuevo, es casi como escribir lo que tenemos en la cabeza.

Si la nota es mayor que 10 ó es menor que 0
    avisamos que la nota está fuera de rango


Código: [Seleccionar]
if (calificacion > 10 || calificacion < 0)
JOptionPane.showMessageDialog(null, "Introduzca una calificación valida entre 0 y 10 ");

Pregunta si algo no ha quedado claro.

Un saludo.

369
Puedes crear un zip con tus clases .java y adjuntarla a tu mensaje.
O prueba a copiar y pegar el mensaje de error que te aparece, quizás con eso baste para saber que está ocurriendo.

Al margen de esto,  puedes escribir igualmente la clase Producto y una clase que gestione los productos.

La clase que gestione los productos (con un ArrayList de Productos) es posible que no quede completa y se modifique posteriormente según se va construyendo la interfaz.
Pero funciones como añadir un Producto, eliminarlo, guardar y leer de disco... se pueden hacer ya, porque su código es independiente de si luego se usa o no una interfaz, ni de que diseño tendrá.

370
El error que te da al generar ID, es que el atributo lo has declarado como String.
Código: [Seleccionar]
private String id;
El id, en este caso, ha de ser int
Código: [Seleccionar]
private int id;
Otra cosa que has de corregir son los constructores.
Esta clase va a tener dos constructores, uno "normal" y otro que recibe un objeto Paciente a partir del cuál hacer una copia.

En el constructor "normal", no has puesto ningún código.
Y el constructor "por copia", has puesto el código que deberías poner en el constructor "normal".

El constructor "por copia", lo que ha de hacer es obtener del Paciente que recibe, el valor de sus atributos para asignárselos al Paciente que se va a construir.
Código: [Seleccionar]
    /**
    *Constructor de copia
    * @param p
    */
    public Paciente(Paciente p){
        //Escribe aqui tu codigo
         id = p.obtenerId();
         nombre = p.obtenerNombre();
         etc...
       
    }

Fíjate que en este constructor, no es necesario usar la palabra reservada this (aunque muchos programadores gustan de usarla igualmente).
No lo es porque no hay duda de que cuando nombramos a id, nombre, edad, sexo,... nos estamos refiriendo a los atributos de esta clase.

Sí es necesario usarlo en el constructor normal, y esto es porque los valores que se reciben entre paréntesis, se llaman igual que los atributos de la clase.
Código: [Seleccionar]
  public Paciente(String nombre, int edad, String sexo, String padecimiento, String tratamiento){
        this.nombre = nombre;
        etc....
    }
Como se llaman exactamente igual los parámetros recibidos como los atributos, hay que usar this para aclarar cuándo hacemos referencia a los atributos.


Sobre el método equals.
Aquí hay que decidir cuándo dos Pacientes son iguales, o más bien dicho, equivalentes
Esto es decisión del programador, él decide que regla se aplica para considerar si dos objetos son iguales o no.

Puesto que tenemos un atributo id, atributo que se supone ha de ser un identificador único y no deberían existir dos Pacientes con el mismo id, podemos imponer la regla de que dos Pacientes con el mismo id son el mismo Paciente.

Da igual si tienen distinto nombre, edad o sexo... si tienen el mismo id, automáticamente serán considerados la misma entidad.

Esto sirve precisamente para facilitar el poder impedir que tengamos Pacientes con identificadores repetidos.
Suponiendo que guardásemos los Pacientes en alguna colección, como un ArrayList por ejemplo, antes de añadir un Paciente gracias al método equals() podríamos consultar rápidamente si ya hay algún Paciente con el mismo ID que el Paciente que queremos añadir, en cuyo caso rechazaríamos el nuevo Paciente hasta que se le asigne otro ID.

Bien, ¿y cuál es el código para imponer esta regla?
Pues nos basta con una sola línea de código:

Código: [Seleccionar]
    /**
    * Metodo que compara si 2 pacientes son iguales
    * @param p
    * @return boolean - true si son iguales y false si son distintos
    */
    public boolean equals(Paciente p){
        return id == p.id;
    }
Ahí lo que hacemos es comparar el id de ESTE paciente (de nuevo no es necesario usar la palabra this) con el id del Paciente que recibe el método entre paréntesis.
Y retornamos el resultado de esta comparación.
Si los id son iguales, se retornará TRUE, y por lo tanto los dos Pacientes se considerarán equivalentes/iguales.
Si los id son distintos, se retorna FALSE.


Aplica lo que he explicado, pregunta si algo no ha quedado claro, y sigue completando lo que falta.


Cuando hayamos terminado la clase Paciente, se nos piden más cosas pero parece que es modificando una clase llamada HorarioPaciente.java, clase que se supone debes tener de un ejercicio anterior.


371
Hola Daniel.

A ver, nos dan esta clase/archivo Paciente.java para completar:

Código: [Seleccionar]
public class Paciente {

//Escribe los atributos de la clase

    /**
    *Constructor de un paciente asignando todos sus parametros
    * Debes asignar un valor aleatorio a id
    *@param nombre
    *@param edad
    *@param sexo
    *@param padecimiento
    *@param tratamiento
    */
    public Paciente(String nombre, int edad, String sexo, String padecimiento, String tratamiento){
        //Escribe aqui tu codigo
    }

    /**
    *Construcor de copia
    * @param p
    */
    public Paciente(Paciene p){
        //Escribe aqui tu codigo
    }

    /**
    * Método para asignar nombre
    * @param nombre
    */
    public void asignarNombre(String nombre){
        //Escribe aqui tu codigo
    }

    /**
    * Método para asignar edad de manera aleatoria
    */
    public void asignarId(){
        //Escribe aqui tu codigo
    }

    /**
    * Método para asignar edad
    * @param edad
    */
    public void asignarEdad(int Edad){
        //Escribe aqui tu codigo
    }

    /**
    * Método para asignar sexo
    * @param sexo
    */
    public void asignarSexo(String sexo){
        //Escribe aqui tu codigo
    }

    /**
    * Método para asignar padecimiento
    * @param padecimiento
    */
    public void asignarPadecimiento(String padecimiento){
        //Escribe aqui tu codigo
    }

    /**
    * Método para asignar tratamiento
    * @param tratamiento
    */
    public void asignarTratamiento(String tratamiento){
        //Escribe aqui tu codigo
    }

    /**
    * Método para obtener nombre
    * @return nombre
    */
    public String obtenerNombre(){
        //Escribe aqui tu codigo
    }

    /**
    * Método para obtener edad
    * @return edad
    */
    public int obtenerEdad(){
        //Escribe aqui tu codigo
    }

    /**
    * Método para obtener id
    * @return id
    */
    public int obtenerId(){
        //Escribe aqui tu codigo
    }

    /**
    * Método para obtener sexo
    * @return sexo
    */
    public String obtenerSexo(){
        //Escribe aqui tu codigo
    }

    /**
    * Método para obtener padecimiento
    * @return padecimiento
    */
    public String obtenerPadecimiento(){
        //Escribe aqui tu codigo
    }

    /**
    * Método para obtener tratamiento
    * @return tratamiento
    */
    public String obtenerTratamiento(){
        //Escribe aqui tu codigo
    }

    /**
    * Metodo que compara si 2 pacientes son iguales
    * @param p
    * @return boolean - true si son iguales y false si son distintos
    */
    public boolean equals(Paciente p){
        //Escribe aqui tu codigo
    }

    /**
    * Metodo que imprime un paciente
    * @return String que incluye todos los atributos del paciente
    */
    public String toString(){
        //Escribe aqui tu codigo
    }

    /**
    * Metodo que simula si un paciente ya recibio su tratamiento
    * @param esHora - entero que da la relación de orden entre
    * dos horas. >0, <0, =0
    * @return String  - mensaje de si ya tomo su medicamento, si ya es hora
    * de tomarlo o si aun no es la hora.
    */

    public String aplicarTratamiento(int esHora){
        //Escribe aqui tu codigo
    }

}

Y estos son los pasos a seguir:
Citar
(a) Declarar los atributos : nombre, edad,sexo, padecimiento, tratamiento
e id, los cuales deben ser privados.
(b) Programar un constructor por par ́ametros. El id se deber ́a calcular
autom ́aticamente. HINT: Revisa la biblioteca Random, en especial
el m ́etodo nextInt(). Enlace de referencia sobre su uso
(c) Programar un constructor de copia.
(d) Programar los m ́etodos de acceso y modificadores.
(e) Programar un m ́etodo equals() que compare si 2 pacientes son iguales.

(f) Programar un m ́etodo toString() que imprima como el siguiente ejem-
plo:


(g) Programar un m ́etodo llamado aplicarTratamiento() que simule la
aplicaci ́on del tratamiento. Este recibir ́a un int que representa la
relaci ́on entre 2 horas para simular si ya tomo el medicamento o no
dependiendo la hora. HINT: Debes utilizar un m ́etodo de Hora que
te indica si una hora es mayor, igual o menor que otra Hora.


Pues comienza, ves haciendo lo que puedas y lo que no te salga o veamos que pueda estar mal te ayudamos a corregirlo.
Por ejemplo, el primer paso que es declarar los atributos, no creo que te suponga un problema.
Hazlo, continúa con el resto y lo que no consigas, muestras por aquí tu código y te vamos ayudando.

372
Pues es similar al anterior, solo que con Productos en lugar de Casos

Comienza por pensar como será la clase para modelar los productos.
Hay varios productos: juguetes, equipos, celulares, muebles...

Se podría hacer una clase para cada tipo, pero como son todos exactamente iguales en cuanto atributos y métodos, parece más eficiente hacer una sola clase llamada Producto y usar un atributo String para distinguir el tipo de producto del que se trata.
Estos podrían ser los atributos:
Código: [Seleccionar]
String codigo;
String tipoProducto; //juguetes, equipos, celulares, muebles...
String marca;
String modelo;
float precioCompra;
float precioVenta;
int stock;

Escribe esta clase y vamos continuando a partir de ahí.

De hecho, se pueden replicar los pasos que yo seguí en el ejercicio anterior.
- Hacer clase Producto.
- Hacer clase que gestiona los Productos
- Diseñar la interfaz
- Aplicar funcionalidad a la interfaz para que interactue con la gestión de productos.

373
Hola HeyMrDave
Gracias por tu aportación.

Usar negativos como índice en vectores puede funcionar en C/C++, pero no en la mayoría de lenguajes, así que no puede tomarse como una solución de uso general.
Aunque está bien comentarla.

Por otra parte, tampoco se sí es algo que depende del compilador.
Si por ejemplo pruebo tu código en este compilador online: https://www.online-ide.com/FVug3D20z4

No da buen resultado:
Citar
4
10
20
30
40

10 20 30 40
0 10 20 30

** Process exited - Return Code: 0 **

Claro que quizás no es el mejor sitio para probarlo.

Un saludo.

374
Ufff... veo un montón de clases, cuando lo que se pide no es tanto. No sé si modificar y adaptar ese código es el camino...

Echarle un vistazo para inspirarse tal vez..., pero adaptarlo, puede ser más complicado que comenzar uno nuevo.

Te dejo una propuesta para solucionarlo, a ver si te es útil.

Comenzamos con la clase Venta.

Se crea una fecha completa para el atributo, pero luego para guardar los datos en el archivo de texto, solo se guarda el año (ignoro mes y día) porque es el dato importante para los posteriores cálculos.

Uso un método que retorna un String con los atributos separados por comas, que serán las líneas que se guardarán en el archivo de texto.

Código: [Seleccionar]
import java.time.LocalDate;
import java.util.Random;

public class Venta {

private String codigo;
private String ciudad;
private LocalDate fecha;
private int valor;

public Venta(int numCodigo) {
codigo = String.format("U%07d", numCodigo); //Formato U0000001
Random azar = new Random();
ciudad = ciudadRandom(azar);
int year = azar.nextInt(5) + 2016; //Año entre 2016 y 2020
int mes = azar.nextInt(12) + 1;
int dia;
if (mes == 2)
dia = azar.nextInt(28) + 1;
else
dia = azar.nextInt(30) + 1;
fecha = LocalDate.of(year, mes, dia);
valor = azar.nextInt(5000) + 1;
}

private String ciudadRandom(Random rnd) {
final String[] ciudades = {"Manta","Portoviejo","Chone","Montecristi","Jipijapa"};
return ciudades[rnd.nextInt(ciudades.length)];
}

public String toTXT() {
//De la fecha solo se guarda el año porque es el dato que importa
return String.format("%s,%s,%d,%d", codigo, ciudad, fecha.getYear(), valor);
}

}

Bien, vamos a ver los hilos.
Hay que crear dos clases que hereden de Thread, es decir, dos tipos de hilo. Cada hilo hará distintos cálculos con los datos del archivo de texto que luego crearemos.

Estos hilos, además de hacer sus cálculos, modificarán el formulario (la interfaz gráfica) mostrando ellos mismos los resultados obtenidos.
No he sabido ver cómo es el formulario del ejercicio de ejemplo. Yo he optado por usar dos áreas de texto, una para cada hilo, y además tendrán una barra de progreso que se incrementarán durante el tiempo que dure el proceso del hilo.

Así que estos hilos se encargarán de leer las líneas del archivo, buscar los datos que necesitan, computar, actualizar la barra de progreso y finalmente mostrar los datos computados en el área de texto.

Para que estos hilos sepan con cuál barra progreso y área de texto han de interactuar, usaré unos setter para hacerles llegar las referencias de los correspondientes elementos del formulario con los que han de trabajar.

Esta sería la clase Hilo1

Código: [Seleccionar]
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.JTextArea;

/**
 * Suma de valores>3000 de los años 2017, 2018, 2019
 */
public class Hilo1 extends Thread{

private JProgressBar progreso;
private JTextArea texto;

public void setProgreso(JProgressBar progreso) {
this.progreso = progreso;
}

public void setTexto(JTextArea texto) {
this.texto = texto;
}

@Override
public void run() {
progreso.setValue(0);
texto.setText("      Suma de valores > 3000 de los años 2017, 2018, 2019\n"
+ "      ----------------------------------------------------------------------------\n\n");
int sumaValores = 0;
File archivo = new File("DatosVentas.txt");

try {
long inicio = System.currentTimeMillis();
BufferedReader lector = new BufferedReader(new FileReader(archivo));
String linea = lector.readLine();
while (linea != null) {
progreso.setValue(progreso.getValue() + 1);
String[] datos = linea.split(",");
int year = Integer.parseInt(datos[2]);
if (year >= 2017 && year <= 2019) {
int valor = Integer.parseInt(datos[3]);
if (valor > 3000)
sumaValores += valor;
}
linea = lector.readLine();
}
lector.close();
long fin = System.currentTimeMillis();
//Resultados
texto.append("Suma: " + sumaValores);
texto.append("\nTiempo: " + (fin - inicio) + " ms");
} catch (FileNotFoundException e) {
JOptionPane.showMessageDialog(null, "No hay archivo de datos.", "Calculos de Hilo1",
JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Error accediendo a:\n" + archivo.getAbsolutePath(),
"Calculos de Hilo1", JOptionPane.ERROR_MESSAGE);
}
}

}

Y esta Hilo2. Prácticamente son idénticas, solo cambian los datos que computan.
Código: [Seleccionar]
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.JTextArea;

/**
 * De los años 2018, 2019, 2020 cual es el valor menor y mayor
 */
public class Hilo2 extends Thread{

private JProgressBar progreso;
private JTextArea texto;

public void setProgreso(JProgressBar progreso) {
this.progreso = progreso;
}

public void setTexto(JTextArea texto) {
this.texto = texto;
}

@Override
public void run() {
progreso.setValue(0);
texto.setText("      De los años 2018, 2019, 2020 calcular valor menor y mayor\n"
+ "      ----------------------------------------------------------------------------------\n\n");
int menor = 5001;
int mayor = 0;
File archivo = new File("DatosVentas.txt");

try {
long inicio = System.currentTimeMillis();
BufferedReader lector = new BufferedReader(new FileReader(archivo));
String linea = lector.readLine();
while (linea != null) {
progreso.setValue(progreso.getValue() + 1);
String[] datos = linea.split(",");
int year = Integer.parseInt(datos[2]);
if (year >= 2018 && year <= 2020) {
int valor = Integer.parseInt(datos[3]);
if (valor > mayor)
mayor = valor;
if (valor < menor)
menor = valor;
}
linea = lector.readLine();
}
lector.close();
long fin = System.currentTimeMillis();
//Resultados
texto.append("Mayor: " + mayor);
texto.append("\nMenor: " + menor);
texto.append("\nTiempo: " + (fin - inicio) + " ms");
} catch (FileNotFoundException e) {
JOptionPane.showMessageDialog(null, "No hay archivo de datos.", "Calculos de Hilo2",
JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Error accediendo a:\n" + archivo.getAbsolutePath(),
"Calculos de Hilo2", JOptionPane.ERROR_MESSAGE);
}
}

}

Bien, ya tendríamos los hilos.
Vamos a ver la interfaz del programa.

Este es el diseño que he creado:




Hay un botón para generar un archivo con los datos de ventas y otro botón para dar comienzo a los cálculos.

Al pulsar este último botón, se iniciarán los dos hilos y los resultados se verán en los dos paneles centrales.


Bien, el panel superior con el botón para crear el archivo, es un panel que he escrito como una clase separada porque tiene bastante líneas de código y además es completamente autónomo, no necesita interactuar con el resto de elementos de la interfaz, así que puede escribirse como una clase individual.

Esta clase usa un BufferedWriter dentro de un bucle para crear objetos de la clase Venta y escribir una línea de texto con los datos en un archivo.
El programa pide crear 2 millones de registros (el archivo superará los 50MB de peso..  :o), esto puede requerir unos cuantos segundos según la potencia de computación de cada PC, así que antes de crear el archivo se muestra un mensaje advirtiendo de esto, para que el usuario sea consciente y sepa que ha de esperar.
Una vez creado el archivo, también se avisa al usuario para que sepa que el proceso ya se ha completado.

Esta es la clase PanelCrear

Código: [Seleccionar]
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class PanelCrear extends JPanel{

private JButton btCrear;

public PanelCrear() {
btCrear = new JButton("Crear nuevo fichero de datos");
btCrear.addActionListener(new AccionCrear());
add(btCrear);
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(25, 25, 25, 25),
BorderFactory.createLoweredSoftBevelBorder()));
}

private class AccionCrear implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null, "A continuación se creará un archivo con 2 millones de líneas."
+ "\nEsto puede tardar unos segundos según las capacidades de tu PC.\nTen paciencia...",
"Crear Archivo", JOptionPane.WARNING_MESSAGE);
File archivo = new File("DatosVentas.txt");
try {
BufferedWriter escritor = new BufferedWriter(new FileWriter(archivo, false));
//Creamos 2 millones de registros
for (int i = 1; i <= 2000000; i++) {
Venta nueva = new Venta(i); //Generamos nueva VENTA
escritor.write(nueva.toTXT()); //Creamos una línea de texto con los datos de la VENTA
escritor.newLine();
}
escritor.close();
JOptionPane.showMessageDialog(null, "Nuevos datos creados en:\n" + archivo.getAbsolutePath(),
"Crear Archivo", JOptionPane.INFORMATION_MESSAGE);
} catch (IOException e1) {
JOptionPane.showMessageDialog(null, "No se pudo crear archivo:\n" + archivo.getAbsolutePath(),
"Crear Archivo", JOptionPane.ERROR_MESSAGE);
}

}
}

}

Vamos a ver ahora los paneles que muestran el area de texto y la barra de progreso.
Se trata de una única clase, que mediante constructor recibe un entero entre 1 y 2 para indicarle si ha de trabajar con Hilo1 o con Hilo2.

Así no hay que escribir dos clases distintas, basta con escribir solo una.

En realidad es una clase con poco código.

Inicializa el area de texto y la barra de progreso.

Luego tiene un método llamado calcular() que según el tipo de hilo que se le haya indicado, configura e inicia un Hilo1 o un Hilo2

Así, con una sola clase, podemos disponer de dos paneles para cada tipo de hilo.

Esta es la clase PanelHilo

Código: [Seleccionar]
import java.awt.BorderLayout;

import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextArea;
import javax.swing.border.EtchedBorder;

public class PanelHilo extends JPanel{

private JProgressBar barraProgreso;
private JTextArea areaTexto;
int tipoHilo; //Se le indica al panel si ha de usar un Hilo1 o un Hilo2

public PanelHilo(int hilo) {
barraProgreso = new JProgressBar(0,2000000);
barraProgreso.setStringPainted(true);
areaTexto = new JTextArea(10, 33);
areaTexto.setEditable(false);
tipoHilo = hilo;

setLayout(new BorderLayout());
JPanel pnBarra = new JPanel();
pnBarra.add(barraProgreso);
pnBarra.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(15,15,15,15),
BorderFactory.createRaisedSoftBevelBorder()));

JPanel pnArea = new JPanel();
pnArea.add(areaTexto);
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("Hilo " + tipoHilo),
BorderFactory.createEtchedBorder(EtchedBorder.RAISED)));

add(pnBarra, BorderLayout.NORTH);
add(pnArea, BorderLayout.CENTER);
}

public void calcular() {
//Instanciamos un Hilo1 o un Hilo2 según el atributo tipoHilo
if (tipoHilo == 1) {
Hilo1 hiloCalculos = new Hilo1();
hiloCalculos.setProgreso(barraProgreso);
hiloCalculos.setTexto(areaTexto);
hiloCalculos.start();
}
else {
Hilo2 hiloCalculos = new Hilo2();
hiloCalculos.setProgreso(barraProgreso);
hiloCalculos.setTexto(areaTexto);
hiloCalculos.start();
}
}

}

Ya solo queda la clase principal. Es un JFrame que utiliza las clases JPanel que hemos visto antes y además añade el botón para iniciar los cálculos.

Al pulsar este botón se comprueba si existe o no un fichero de datos.

Si no existe, se avisa y no se hacen cómputos (porque no se puede).

Si existe, se le pide a los dos PanelHilo mediante el método calcular() que inicien sus correspondientes hilos.

Y enseguida podremos ver los resultados en pantalla.

Esta es la clase Formulario

Código: [Seleccionar]
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Formulario extends JFrame{

private PanelHilo pnHilo1;
private PanelHilo pnHilo2;
private JButton btIniciar;

public Formulario() {
pnHilo1 = new PanelHilo(1); //Especificamos que "tipo" de hilo ha de usar
pnHilo2 = new PanelHilo(2);

JPanel pnHilos = new JPanel();
pnHilos.add(pnHilo1);
pnHilos.add(pnHilo2);

btIniciar = new JButton("Iniciar Calculos");
btIniciar.addActionListener(new AccionIniciar());
JPanel pnIniciar = new JPanel();
pnIniciar.add(btIniciar);

setLayout(new BorderLayout());
add(new PanelCrear(), BorderLayout.NORTH);
add(pnHilos, BorderLayout.CENTER);
add(pnIniciar, BorderLayout.SOUTH);

setTitle("Calculos con Hilos");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Formulario();
}
});
}




Y creo que con esto ya se tiene lo que se pide.

A ver si te sirve, y pregunta cualquier cosa que no entiendas.

Un saludo.

375
Hace un par de meses tratamos este mismo ejercicio en otro tema.

Puede que la solución ahí propuesta te sirva.

376
Gracias por tu aportación  ;)

El close() suelo ponerlo más que nada para que Eclipse no me señale la clase con un warning, que me da mucha tirria  :P

El "var" me resisto a usarlo en los ejemplos porque hay muchísimos estudiantes que en sus centros de estudios compilan con JDK's antiguos, así que intento que el código sea lo más retrocompatible posible.

De nuevo agradezco tu aportación, espero poder ver muchas más por aquí.
Un saludo.

377
Los métodos se han de declarar fuera del método main, no dentro:

Citar
        static void Main(string[] args)
        {

            double PorPrecio(double num1, double num2)
            {
                double resultado = num1 / num2;
                return resultado;
            }




            double PorLitro(double num1, double num2)
            {
                double resultado = num1 * num2;
                return resultado;
            }

Y los declarar también static, igual que el main, para que puedan invocarse directamente sin tener que instanciar ningún objeto.

Luego prueba tu mismo a ejecutarlo, a ver si funciona o no.

Luego puedes comparar con el código que puse. Yo le di un enfoque algo distinto, por ejemplo a los métodos les hago llegar el tipo de combustible para que sean ellos los que hagan el switch.
Pero en esencia ambas soluciones son muy similares.

Por cierto, voy a poner aquí el código porque el enlace que puse tarde o temprano caducará.

Código: [Seleccionar]
using System;

namespace EstacionServicio
{
    class Program
    {
        static class Precios
        {
            //Dolares por litro
            public const float Infinia = 117.1f;
            public const float Super = 101.6f;
            public const float Diesel = 92.2f;
            public const float InfiniaDiesel = 112.8f;
        }
        static void Main(string[] args)
        {
           

            string nombre = "";

            while (!nombre.Equals("ZZZ"))
            {
                Console.Write("Nombre Cliente: ");
                nombre = Console.ReadLine();
                if (!nombre.Equals("ZZZ"))
                {
                    float importe, capacidad;
                    string tipoCombustible = PedirTipoCombustible();
                    string modalidad = PedirModalidad();

                    if (modalidad.Equals("C"))
                    {
                        Console.Write("\nIndique capacidad deseada en litros: ");
                        capacidad = float.Parse(Console.ReadLine());
                        importe = PorCapacidad(capacidad, tipoCombustible);
                    }
                    else
                    {
                        Console.Write("\nIndique el importe en dolares: ");
                        importe = float.Parse(Console.ReadLine());
                        capacidad = PorPrecio(importe, tipoCombustible);
                    }

                    //Detallamos tiquet
                    Console.Clear();
                    Console.WriteLine("\t\tTIQUET OPERACION");
                    Console.WriteLine("Nombre: {0}", nombre);
                    Console.WriteLine("Tipo Combustible: {0}", tipoCombustible);
                    Console.WriteLine("Combustible cargado(litros): {0}", capacidad.ToString("0.##"));
                    Console.WriteLine("Importe Total: {0}", importe.ToString("0,0.00"));
                    Console.ReadKey();
                    Console.Clear();
                }
            }
           
        }

        static string PedirTipoCombustible()
        {
            string[] tipos = new string[] { "I", "S", "D", "ID" };
            string tipo = "";
            bool repetir = true;
            while (repetir)
            {
                Console.WriteLine("\n[I] -- Infinia");
                Console.WriteLine("[S] -- Super");
                Console.WriteLine("[D] -- Diesel");
                Console.WriteLine("[ID] -- InfiniaDiesel");
                Console.Write("Elija tipo: ");
                tipo = Console.ReadLine().ToUpper();
                //Si el tipo introducido consta en el array de posibles tipos, el bucle termina
                if (Array.Exists(tipos, x => x == tipo))
                    repetir = false;
            }

            return tipo;
        }

        static string PedirModalidad()
        {
            string modo = "";

            while (!modo.Equals("C") && !modo.Equals("P"))
            {
                Console.WriteLine("\n[C] -- Por Capacidad");
                Console.WriteLine("[P] -- Por Precio");
                Console.Write("Elija modalidad: ");
                modo = Console.ReadLine().ToUpper();
            }

            return modo;
        }

        static float PorCapacidad(float litros, string tipo)
        {
            switch(tipo)
            {
                case "I":
                    return litros * Precios.Infinia;
                case "S":
                    return litros * Precios.Super;
                case "D":
                    return litros * Precios.Diesel;
                case "ID":
                    return litros * Precios.InfiniaDiesel;
                default:
                    return 0;
            }
        }

        static float PorPrecio(float importe, string tipo)
        {
            switch (tipo)
            {
                case "I":
                    return importe / Precios.Infinia;
                case "S":
                    return importe / Precios.Super;
                case "D":
                    return importe / Precios.Diesel;
                case "ID":
                    return importe / Precios.InfiniaDiesel;
                default:
                    return 0;
            }
        }
    }
}

378
La clase Main reúne los tres paneles de la "Vista" y el gestor de casos del "Modelo" en una única clase para que puedan interactuar entre ellos, así que esta clase cumpliría la función de "Controlador".

Es un JFrame y además tiene el código de los listeners que aplicaremos a algunos botones y a la tabla. Estos listeners es necesario escribirlos aquí porque es donde Vista y Modelo comparten el mismo ámbito y es posible interactuar entre ellos.

Por ejemplo, cuando pulsamos el botón "Eliminar":
- hay que pedirle al gestor de casos que elimine el caso seleccionado del ArrayList
- hay que pedirle a la tabla que se actualice para dejar de mostrar el caso eliminado
- hay que pedirle al panel de datos (formulario) que deje de mostrar los datos del caso eliminado.

Si la acción (ActionListener) que hace todo esto la hubieramos escrito en la clase PanelDatos, donde se encuentra el botón que ha de realizar esta acción, no sería posible porque desde PanelDatos no hay referencia con la tabla, por ejemplo, y no se le podría pedir que se actualizase.

Por eso estos Listeners conviene escribirlos en la clase que haga la función de "Controlador", la clase Main en nuestro caso.

Código: [Seleccionar]
package gui;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.SwingUtilities;

import casos.*;

public class Main extends JFrame{

private GestionCasos gestor;
private PanelDatos pnDatos;
private PanelTabla pnTabla;

public Main() {

gestor = new GestionCasos();
pnDatos = new PanelDatos();
pnDatos.btEliminar.addActionListener(new AccionEliminar());
pnDatos.btGuardar.addActionListener(new AccionGuardar());
pnDatos.btGrabar.addActionListener(new AccionGrabar());
pnTabla = new PanelTabla(gestor.registroCasos);
pnTabla.setTablaListener(new TablaListener());

JPanel pnNorte = new JPanel(); //Este panel contendrá el panel con imagen
pnNorte.add(new PanelImagen("gui/covid.png"));

JPanel pnCentro = new JPanel(); //Este panel reune el formulario y la tabla
pnCentro.setLayout(new BoxLayout(pnCentro, BoxLayout.Y_AXIS));
pnCentro.add(pnDatos);
pnCentro.add(new JSeparator());
pnCentro.add(pnTabla);
pnCentro.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));

setLayout(new BorderLayout());
add(pnNorte, BorderLayout.NORTH);
add(pnCentro, BorderLayout.CENTER);

setTitle("Registro Covid-19");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setResizable(false);
setLocationRelativeTo(null);
setVisible(true);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Main();
}
});
}

//Listeners
private class AccionGuardar implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
//Pedimos Caso al formulario
Caso caso = pnDatos.getCaso();
if (caso != null) { //Si datos de formulario son incompletos, no habría Caso

if (pnDatos.esModificacion())
gestor.modificarCaso(caso, pnTabla.getSeleccionado());
else
gestor.registrarCaso(caso);

pnTabla.actualizarTabla();
}
}
}

private class AccionGrabar implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
gestor.guardarRegistro();
}
}

private class AccionEliminar implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
int respuesta = JOptionPane.showConfirmDialog(null, "¿Eliminar el registro seleccionado?",
"Eliminar Registro", JOptionPane.YES_NO_OPTION);
if (respuesta == JOptionPane.YES_OPTION) {
int seleccionado = pnTabla.getSeleccionado();
gestor.eliminarCaso(seleccionado);
pnTabla.actualizarTabla();
pnDatos.seleccionarCaso(null);
JOptionPane.showMessageDialog(null, "Registro Eliminado."
+ "\nRecuerde grabar en disco para que el cambio sea persistente",
"Eliminar Registro", JOptionPane.INFORMATION_MESSAGE);
}
}
}

/**
* Este es el Listener para la tabla.
* Simplemente detecta que Caso de la tabla ha sido clickado
* y se lo comunica al panel de datos para que configure ese Caso
* como seleccionado.
*/
private class TablaListener implements MouseListener {
@Override
public void mouseClicked(MouseEvent e) {
int seleccionado = pnTabla.getSeleccionado();
pnDatos.seleccionarCaso(gestor.getCaso(seleccionado));
}

@Override
public void mousePressed(MouseEvent e) { }

@Override
public void mouseReleased(MouseEvent e) { }

@Override
public void mouseEntered(MouseEvent e) { }

@Override
public void mouseExited(MouseEvent e) { }
}
}


Y con esto ya tendríamos la aplicación completada.
No he comentado detalladamente cada aspecto del programa porque llevaría mucho tiempo, aquello que no se entienda, haced aquí la pregunta y lo explico.

Adjunto un zip con los packages del código.

La imagen que utilicé es esta: https://i.ibb.co/TgG6QK0/covid.png

Un saludo.

379
La interfaz podría ser algo así:

Una imagen de encabezado (podría ser un logo de un hospital o cualquier otra cosa). Un panel de datos del caso con nombre, apellidos, género, edad, estado y prueba covid confirmado sí/no. A su vez, botones "Nuevo registro", "Modificar", "Eliminar", "Guardar", "Grabar" y "Salir". Una tabla de datos de pacientes con nombre, apellidos, género, edad, confirmado, estado (recuperado/activo/fallecido...).



La ventana está dividida en tres partes.

Arriba simplemente se muestra la imagen de Covid, para darle un poquito más de vistosidad a la aplicación.

Debajo hay un formulario para insertar y modificar los datos, junto con botones para las distintas funciones.

Abajo de todo, una tabla (no editable, para simplificar el código) en la que se muestran los casos registrados.

Al pinchar en uno de esos casos, los datos se muestran en los campos del formulario.
Si se pulsa el botón "Modificar" entonces se permite modificar los valores en el formulario y con el botón "Guardar" se aceptan los cambios.

Sin embargo, este botón solo guarda los cambios en memoria (en el ArrayList). Si se quiere hacerlos persistentes hay que pulsar el botón "Grabar" para que se guarden los cambios en disco.

Bien, estas tres partes de la ventana, están creadas con tres clases distintas que heredan de JPanel.

La primera clase, PanelImagen, es muy sencilla, se encarga simplemente de "pintar" un panel con la imagen que le indiquemos por su constructor:


Código: [Seleccionar]
package gui;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class PanelImagen extends JPanel{

private Image imagen;

public PanelImagen(String rutaImagen) {
imagen = new ImageIcon(getClass().getClassLoader().getResource(rutaImagen)).getImage();
setPreferredSize(new Dimension(599, 158));
}

@Override
public void paint(Graphics g){
g.drawImage(imagen, 0, 0, 599, 158, this);
setOpaque(false);
super.paint(g);
}
}

La segunda, PanelDatos, muestra el formulario y los botones de funciones.

Está a su vez dividida en dos subpaneles, uno con los campos de texto, combobox, el checkbox, etc ..

Y otro con la línea de botones.

Algunos botones, sus acciones (ActionListener) están escritos en esta misma clase porque son acciones sencillas que no necesitan interactuar con otras partes del código.
Por ejemplo el botón "SALIR" para cerrar la aplicación o el botón "Nuevo Registro" que lo único que hace es limpiar los campos y activarlos para que se pueda escribir en ellos.

Otros botones, sus acciones se escribirán desde otra parte del código, porque si tendrán que interactuar con el "gestor de casos" y/o con el panel que mostrará la tabla.

Hay que destacar que este panel tiene un objeto Caso como atributo. Este atributo es una referencia al Caso que consta como seleccionado en la tabla. Tener esta referencia facilita saber de quién son los datos que hay que mostrar y/o modificar en los campos.

Código: [Seleccionar]
package gui;

import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;

import casos.Caso;

public class PanelDatos extends JPanel{

//Referencia a caso seleccionado en tabla
private Caso casoSeleccionado = null;

private JTextField jtNombre;
private JTextField jtApellidos;
private JComboBox<String> comboGenero;
private JSpinner jsEdad;
private JCheckBox checkConfirmado;
private JComboBox<String> comboEstado;
private JButton btNuevo;
public JButton btModificar;
public JButton btEliminar;
public JButton btGuardar;
public JButton btGrabar;
private JButton btSalir;

public PanelDatos() {
iniciarComponentes();
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(new PanelRegistro());
add(new PanelBotones());
nuevoRegistro(); //Formulario inicia listo para crear un nuevo registro
}

private void iniciarComponentes() {
jtNombre = new JTextField(12);
jtApellidos = new JTextField(18);
comboGenero = new JComboBox<String>(new String[] {"Hombre", "Mujer"});
jsEdad = new JSpinner(new SpinnerNumberModel(18, 0, 99, 1));
checkConfirmado = new JCheckBox("Confirmado");
comboEstado = new JComboBox<String>(new String[] {"Activo", "Recuperado", "Fallecido"});
btNuevo = new JButton("<html><p style=\"text-align:center\">Nuevo<br>Registro</p></html>");
btNuevo.addActionListener(new AccionNuevo());
btModificar = new JButton("Modificar");
btModificar.addActionListener(new AccionModificar());
btEliminar = new JButton("Eliminar");
btGuardar = new JButton("Guardar");
btGrabar = new JButton("Grabar");
btSalir = new JButton("SALIR");
btSalir.addActionListener(new AccionSalir());
}

//Paneles
private class PanelRegistro extends JPanel {

public PanelRegistro() {
setLayout(new GridLayout(3,2,5,10));
add(new PanelConLabel("Nombre", jtNombre));
add(new PanelConLabel("Apellidos", jtApellidos));
add(new PanelConLabel("Genero", comboGenero));
add(new PanelConLabel("Edad", jsEdad));
add(new PanelConLabel("Estado", comboEstado));
add(new PanelConLabel("Prueba COVID", checkConfirmado));

setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(10, 10, 5, 10),
BorderFactory.createTitledBorder("Datos del Caso")));
}
}

private class PanelBotones extends JPanel {

public PanelBotones() {
add(btNuevo);
add(Box.createHorizontalStrut(20));
add(btModificar);
add(btEliminar);
add(btGuardar);
add(Box.createHorizontalStrut(20));
add(btGrabar);
add(btSalir);

setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(5, 10, 10, 10),
BorderFactory.createLoweredSoftBevelBorder()));
}
}

private class PanelConLabel extends JPanel {

public PanelConLabel(String textoLabel, JComponent componente) {
setLayout(new FlowLayout(FlowLayout.LEFT));
add(new JLabel(textoLabel));
add(componente);
}
}

//Acciones
private class AccionNuevo implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
nuevoRegistro();
}
}

private class AccionModificar implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
btModificar.setEnabled(false);
btGuardar.setEnabled(true);
btGrabar.setEnabled(false);
activarCampos(true);
}
}

private class AccionSalir implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
int resp = JOptionPane.showConfirmDialog(null, "¿Cerrar Programa?"
+ "\nSe perderán los datos no GRABADOS.", "Cerrar Programa", JOptionPane.YES_NO_OPTION);
if (resp == JOptionPane.YES_OPTION)
System.exit(0);
}
}

//Métodos
/**
* Activa o desactiva los campos del formulario.<br>
* Los campos solo se activan cuando se está haciendo un nuevo
* registro o cuando se va a modificar un Caso existente.
* @param activar True para activar, False para desactivar
*/
private void activarCampos(boolean activar) {
jtNombre.setEditable(activar);
jtApellidos.setEditable(activar);
comboGenero.setEnabled(activar);
jsEdad.setEnabled(activar);
checkConfirmado.setEnabled(activar);
comboEstado.setEnabled(activar);
}

/**
* Prepara el formulario para registrar un nuevo caso.
*/
public void nuevoRegistro() {
casoSeleccionado = null; //Anulamos cualquier referencia a un caso ya existente
jtNombre.setText(null);
jtApellidos.setText(null);
comboGenero.setSelectedIndex(0);
jsEdad.setValue(18);
checkConfirmado.setSelected(false);
comboEstado.setSelectedIndex(0);
activarCampos(true);
btModificar.setEnabled(false);
btEliminar.setEnabled(false);
btGuardar.setEnabled(true);
btGrabar.setEnabled(false);
}

/**
* Comprueba que el formulario tenga los datos necesarios
* para crear un Caso y lo retorna.<br>Este método se invoca
* cuando se pulsa el botón "Guardar" de la interfaz.
* @return Un Caso con los datos del formulario
*/
public Caso getCaso() {
//Construimos un Caso con los datos del formulario
String nombre = jtNombre.getText();
if (nombre.isBlank()) {
JOptionPane.showMessageDialog(null, "Campo NOMBRE no puede estar vacío",
"Guardar Caso", JOptionPane.WARNING_MESSAGE);
return null;
}
String apellidos = jtApellidos.getText();
if (apellidos.isBlank()) {
JOptionPane.showMessageDialog(null, "Campo APELLIDOS no puede estar vacío",
"Guardar Caso", JOptionPane.WARNING_MESSAGE);
return null;
}
String genero = (String) comboGenero.getSelectedItem();
int edad = (int) jsEdad.getValue();
boolean confirmado = checkConfirmado.isSelected();
String estado  = (String) comboEstado.getSelectedItem();

Caso caso = new Caso(nombre, apellidos, genero, edad, confirmado, estado);

//Antes de retornar el Caso, cambiamos configuración de botones interfaz
btModificar.setEnabled(true);
btEliminar.setEnabled(true);
btGuardar.setEnabled(false);
btGrabar.setEnabled(true);
activarCampos(false);

return caso;
}

/**
* Indica si estamos modificando un caso existente
* o creando uno nuevo.
* @return True si estamos modificando, False si es nuevo.
*/
public boolean esModificacion() {
//Si hay un caso seleccionado, es que SÍ estamos modificando.
return casoSeleccionado != null;
}

/**
* Recibe el Caso que ha de constar como seleccionado y por
* tanto muestra los datos del dicho Caso en el formulario.
* Si se recibe un valor null, es que en este momento
* no hay ningún caso seleccionado y los campos vuelven a su
* estado por defecto.<br>Este método se invoca cuando se pulsa
* en un registro de la tabla de casos.
* @param caso El Caso que se ha seleccionado.
*/
public void seleccionarCaso(Caso caso) {
casoSeleccionado = caso;
if (casoSeleccionado == null) {
jtNombre.setText(null);
jtApellidos.setText(null);
comboGenero.setSelectedIndex(0);
jsEdad.setValue(18);
checkConfirmado.setSelected(false);
comboEstado.setSelectedIndex(0);
}
else {
jtNombre.setText(casoSeleccionado.getNombre());
jtApellidos.setText(casoSeleccionado.getApellidos());
comboGenero.setSelectedItem(casoSeleccionado.getGenero());
jsEdad.setValue(casoSeleccionado.getEdad());
checkConfirmado.setSelected(casoSeleccionado.isConfirmado());
comboEstado.setSelectedItem(casoSeleccionado.getEstado());
}
activarCampos(false);
btModificar.setEnabled(true);
btEliminar.setEnabled(true);
btGuardar.setEnabled(false);
btGrabar.setEnabled(true);
}
}

La tercera clase, PanelTabla, es solo un panel que muestra una tabla con los datos de los casos registrados.

Esta tabla se construye a partir de los datos del ArrayList que pusimos en la clase GestionCasos, así que para facilitar esta comunicación recibirá una referencia a este ArrayList mediante el constructor de la clase.

Para simplificar el código, el modelo de la tabla está diseñado para que las celdas no se puedan editar.

La tabla solo mostrará los Casos y permitirá seleccionarlos. Pero para modificar los valores, habrá que usar los campos del formulario.

Código: [Seleccionar]
package gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.MouseListener;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.border.BevelBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;

import casos.Caso;

public class PanelTabla extends JPanel{

private ArrayList<Caso> casos; //Referencia al ArrayList de GestionCasos
private MiTabla tablaCovid;

public PanelTabla(ArrayList<Caso> casosCovid) {
casos = casosCovid;
construirTabla();

JScrollPane sp = new JScrollPane(tablaCovid);
sp.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
sp.setPreferredSize(new Dimension(630, 300));
sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

add(sp);
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(10, 10, 10, 10),
BorderFactory.createRaisedSoftBevelBorder()));
}

private class MiTabla extends JTable {

public MiTabla(String[][] datos, String[] nombresColumna) {
super(new DefaultTableModel(datos, nombresColumna) {
@Override
public boolean isCellEditable(int row, int column) {
return false; //Las celdas de esta tabla NO serán editables
}
});
//Pedimos al render que centre los textos en sus celdas.
DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
centerRenderer.setHorizontalAlignment(SwingConstants.CENTER);
setDefaultRenderer(Object.class, centerRenderer);
//Cambiamos alguna fuente y color para los datos de la tabla
setFont(new Font("Verdana", Font.PLAIN , 12));
setForeground(Color.BLUE);
//También cambiamos estilo de fuente a la cabecera
JTableHeader cabecera = getTableHeader();
cabecera.setFont(new Font("Verdana", Font.BOLD , 14));
setAutoResizeMode(AUTO_RESIZE_OFF);
getColumnModel().getColumn(0).setPreferredWidth(135);
getColumnModel().getColumn(1).setPreferredWidth(160);
getColumnModel().getColumn(2).setPreferredWidth(80);
getColumnModel().getColumn(3).setPreferredWidth(50);
getColumnModel().getColumn(4).setPreferredWidth(50);
getColumnModel().getColumn(5).setPreferredWidth(130);
}
}

private void construirTabla() {

final String[] CABECERA = new String[] {"NOMBRE", "APELLIDOS", "GENERO", "EDAD",
"CONF.", "ESTADO"};
//Matriz para datos de la tabla
String[][] datos = new String[casos.size()][6];
for (int fila = 0; fila < datos.length; fila++) {
datos[fila] = casos.get(fila).datosArray();
}
tablaCovid = new MiTabla(datos, CABECERA);
}

public void actualizarTabla() {
DefaultTableModel modelo = (DefaultTableModel) tablaCovid.getModel();
modelo.setRowCount(0);

for (Caso caso: casos)
modelo.addRow(caso.datosArray());
tablaCovid.setModel(modelo);
}

public int getSeleccionado() {
return tablaCovid.getSelectedRow();
}

/**
* Recibe el "listener" que ha aplicarse en esta tabla.<br>
* Este listener detectará que registro de la tabla ha sido seleccionado y
* está escrito en la clase Main, desde donde se puede
* interactuar con las clases necesarias.
* @param listener MouseListener para detectar que registro ha recibido un click de raton.
*/
public void setTablaListener(MouseListener listener) {
tablaCovid.addMouseListener(listener);
}

}

Con estas tres clases, que son tres paneles, se construye el JFrame de la aplicación.
Este JFrame se crea en la clase Main principal y lo vemos en el siguiente mensaje.

380
Veamos.
La clase Caso podría ser algo así:
Código: [Seleccionar]
package casos;

import java.io.Serializable;

public class Caso implements Serializable{

private String nombre;
private String apellidos;
private String genero;
private int edad;
private boolean confirmado; //India si la infeccion ha sido confirmada por algún test COVID
private String estado; //Activo, Recuperado, Fallecido

public Caso(String nombre, String apellidos, String genero,
int edad, boolean confirmado, String estado) {
this.nombre = nombre;
this.apellidos = apellidos;
this.genero = genero;
this.edad = edad;
this.confirmado = confirmado;
this.estado = estado;
}

public String getNombre() {
return nombre;
}

public void setNombre(String nombre) {
this.nombre = nombre;
}

public String getApellidos() {
return apellidos;
}

public void setApellidos(String apellidos) {
this.apellidos = apellidos;
}

public String getGenero() {
return genero;
}

public void setGenero(String genero) {
this.genero = genero;
}

public int getEdad() {
return edad;
}

public void setEdad(int edad) {
this.edad = edad;
}

public boolean isConfirmado() {
return confirmado;
}

public void setConfirmado(boolean confirmado) {
this.confirmado = confirmado;
}

public String getEstado() {
return estado;
}

public void setEstado(String estado) {
this.estado = estado;
}

/**
* Retorna los datos del Caso reunidos en un array.<br>
* Este array se usará para construir la tabla de datos.
* @return Array de String con los datos de este Caso.
*/
public String[] datosArray() {
return new String[] {nombre, apellidos, genero, Integer.toString(edad),
confirmado?"SI":"NO", estado};
}
}

Solo tiene dos cosas "especiales" a destacar.
Una es que implementa la interfaz Serializable. Esto lo necesitaremos porque los casos que se van a registrar hay que guardarlos en disco para que sean persistentes.
Puesto que los iremos registrando en un ArrayList o colección similar, una forma rápida de guardar los datos es hacer una copia directa del ArrayList tal cuál está en memoria.
Y para eso, hay que poder "serializarlo".

Otra cosa a destacar es el último método. Construye un array con los datos de este caso y lo retorna.
Esto facilitará luego poder mostrar los datos en una tabla, porque con este método cada Caso será capaz de darnos el array que debemos insertar en la tabla.

Ahora necesitaríamos una clase que disponga de un ArrayList para guardar los casos y además se encargue de gestionarlos.
Funciones como guardar un nuevo caso, modificar, eliminar o guardar/leer los datos guardados en disco..., las realizará esta clase que podemos llamar GestionCasos
Código: [Seleccionar]
package casos;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

import javax.swing.JOptionPane;

public class GestionCasos{

private final File fichero = new File("registroCovid/covid.dat"); //Archivo donde se guardan los datos
public ArrayList<Caso> registroCasos = new ArrayList<Caso>();

public GestionCasos() {
cargarRegistro();
}

public Caso getCaso(int indice) {
return registroCasos.get(indice);
}

public void registrarCaso(Caso caso) {
registroCasos.add(caso);
}

public void modificarCaso(Caso caso, int posicion) {
registroCasos.set(posicion, caso); //Sustituimos Caso anterior por el mismo Caso, pero modificado
}

public void eliminarCaso(int indice) {
registroCasos.remove(indice);
}

/**
* Hace una copia en disco del ArrayList
*/
public void guardarRegistro() {
try {
if (!fichero.exists())
crearFichero();

ObjectOutputStream escritor = new ObjectOutputStream(new FileOutputStream(fichero));
escritor.writeObject(registroCasos);
escritor.close();
} catch (FileNotFoundException e) {
JOptionPane.showMessageDialog(null, "No se encuentra fichero de registros",
"Guardar Registro", JOptionPane.WARNING_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "No se puede acceder a: " + fichero.getAbsolutePath()
, "Guardar Registro", JOptionPane.WARNING_MESSAGE);
}
}

/**
* Recupera los datos del ArrayList guardado en disco
*/
private void cargarRegistro() {
try {
ObjectInputStream lector = new ObjectInputStream(new FileInputStream(fichero));
registroCasos = (ArrayList<Caso>) lector.readObject();
lector.close();
} catch (FileNotFoundException e) {
JOptionPane.showMessageDialog(null, "No existe fichero con registros.\n"
+ "Se creará uno nuevo", "Cargar Registro", JOptionPane.WARNING_MESSAGE);
crearFichero();
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "No se puede acceder a: " + fichero.getAbsolutePath()
, "Cargar Registro", JOptionPane.WARNING_MESSAGE);
} catch (ClassNotFoundException e) {
JOptionPane.showMessageDialog(null, "Los datos registrados no son válidos.\n"
+ "El programa iniciará con un registro vacío", "Cargar Registro", JOptionPane.WARNING_MESSAGE);
}
}

/**
* Si no existe el archivo de datos, ya sea porque se ha borrado
* o porque es la primera vez que se ejecuta el programa, este método
* intentará crearlo.
*/
private void crearFichero() {
File directorio = new File(fichero.getParent());
directorio.mkdirs(); //Primero creamos la ruta de carpetas donde se ha de guardar el archivo
try {
fichero.createNewFile(); //Luego intentamos crear el archivo
if (!fichero.exists())
JOptionPane.showMessageDialog(null, "No se pudo crear: " + fichero.getAbsolutePath()
, "Crear Registro", JOptionPane.WARNING_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "No se pudo crear: " + fichero.getAbsolutePath()
, "Crear Registro", JOptionPane.WARNING_MESSAGE);
}
}

}

Estas dos clases en principio ya cubrirían lo que sería el "Modelo" del proyecto, es decir, la gestión de datos internos, las tareas que el usuario no ve.

Ahora nos pondremos con lo que sí ve el usuario, lo que se llama la "Vista". O sea, la interfaz gráfica(GUI). Esto lo vemos en el siguiente mensaje.

Páginas: 1 ... 14 15 16 17 18 [19] 20 21 22 23 24 ... 50

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".