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 ... 10 11 12 13 14 [15] 16 17 18 19 20 ... 50
281
JTextField se te quedaría pequeño. Mejor un JTextArea.

Sin embargo, hacer esto va a requerir bastantes cambios en todo el proyecto.
La clase Batalla ahora tendrá que comunicarse de algún modo con ese JTextArea para lanzarle mensajes.
Pero recuerdo que algunos mensajes del combate, los lanzaban las distintas clases Soldado desde sus métodos atacar()..., ¿también habrá que buscarles conexión con el JTextArea o mejor pensar en otra solución?

También, usabamos un Scanner simplemente para pausar la consola de texto, poder leer lo que salía en pantalla, y pulsar la tecla enter para continuar con el siguiente turno de ataque.
Esto ahora no se podrá hacer y lo que vamos a tener van a ser decenas de mensajes a la velocidad de la luz, los combates van a durar apenas unos milisegundos.
Se puede intentar añadir un retardo entre un mensaje y otro..., pero para ello vamos a tener que jugar con hilos (threads)

 Lo ideal sería reescribir el proyecto desde casi cero, ya teniendo en mente que estará destinado a una GUI y no ha mostrarse por consola de texto.
Pero bueno, parcheando por un lado y por otro, supongo que se podrá apañar...


De momento, crearía una nueva clase JPanel, que tenga un botón y un JTextArea.
Le daremos un método para que reciba un String y lo añada como nueva línea al JTextArea. Así abrimos una vía para que otra clase (Batalla) pueda indicarle que ha de ir mostrando.

El botón de este panel, ha de poner en marcha la clase Batalla, la cuál ha de tener acceso a los Ejercitos (Heroes y Bestias) que se encuentran en la clase JFrame principal.
Esto significa que desde este nuevo panel, no podemos llamar a la clase Batalla, porque desde aquí no podemos "ver" a los ejércitos.

Se puede solucionar tal y como hemos hecho en los paneles anteriores, añadir atributos para poder referenciar a esos ejercitos mediante el constructor de este panel.

Pero otra opción, y que podríamos aplicarla aquí para variar un poco, sería escribir el ActionListener de este botón en la clase principal, y luego hacérselo llegar mediante un método.
Así que haremos eso, un método que reciba un ActionListener y lo aplique al botón de este panel.
Código: [Seleccionar]
public class PanelTexto extends JPanel {

private JTextArea areaTexto;
private JButton btLuchar;

public PanelTexto() {
areaTexto = new JTextArea();
areaTexto.setEditable(false);
btLuchar = new JButton("¡Luchar!");

JScrollPane scrollArea = new JScrollPane();
scrollArea.setViewportView(areaTexto);
scrollArea.setPreferredSize(new Dimension(50, 200));
scrollArea.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(10, 20, 20, 20),
BorderFactory.createLoweredSoftBevelBorder()));

JPanel pnBoton = new JPanel();
pnBoton.add(btLuchar);

setLayout(new BorderLayout());
add(pnBoton, BorderLayout.NORTH);
add(scrollArea, BorderLayout.CENTER);
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(0, 10, 10, 10),
BorderFactory.createRaisedSoftBevelBorder()));
}

//La accion de este botón se escribirá en otra clase
public void setAccionBotonLuchar(ActionListener accion) {
btLuchar.addActionListener(accion);
}

public void nuevaLinea(String linea) {
areaTexto.append(linea + "\n");
}

}

Luego veremos como ponemos este panel en el JFrame, pero antes vamos tratar el tema de la clase Batalla y hacer que los mensajes salgan con algo de retraso entre ellos.

Para esto, como dije antes, deberíamos transformar la clase Batalla en un Thread, un hilo.
No se si has trabajado con hilos antes, no son complicados la verdad. Si lo convertimos en un hilo, el proceso de batalla se llevará a cabo por separado del proceso que estará gestionando la interfaz gráfica: ventana, botones, etc..
Eso nos permite cosas como hacer "dormir" ese hilo durante unos milisegundos cada vez que queramos, y así podremos ver como los mensajes van apareciendo en el area de texto de uno en uno, y no todos de golpe como ocurrirá si no lo hacemos en un hilo paralelo.

Para convertir Batalla en un hilo, basta con hacer que herede de la clase Thread y poner el código que queremos que se ejecute en un método llamado run().
Si no quieres "cargarte" la clase que ya tenemos, puedes crear otra nueva.
Yo lo prefiero así y he creado una clase llamada BatallaHilo.
Le vamos a dar tres atributos: dos objetos Ejercito y un objeto PanelTexto, que será una referencia al nuevo panel que acabamos de crear. Así esta clase tendrá acceso a todo lo que necesita, los Ejércitos para que se líen a mamporrazos entre ellos y el área de texto donde ir publicando los detalles de la contienda.

En el método run(), vamos a poner el mismo código que teníamos en el método estático llamado batallar() de la anterior clase Batalla.
El código va a ser el mismo, pero los System.out.println() los vamos cambiar por llamadas al PanelTexto donde le pasamos los Strings para que los muestre en el JTextArea.

Es decir, donde antes hacíamos esto:
Código: [Seleccionar]
System.out.println(bestia.getNombre() + " ha muerto.");Ahora haremos:
Código: [Seleccionar]
pnTexto.nuevaLinea(bestia.getNombre() + " ha muerto.");
El método pausa() donde antes usábamos el Scanner para detener la consola, ahora lo vamos a cambiar por un código que hará dormitar el hilo durante los milisegundos que queramos indicarle.
Esta sería la clase BatallaHilo
Código: [Seleccionar]
public class BatallaHilo extends Thread {

private Ejercito heroes;
private Ejercito bestias;
private PanelTexto pnTexto;

public BatallaHilo(Ejercito heroes, Ejercito bestias, PanelTexto pnTexto) {
this.heroes = heroes;
this.bestias = bestias;
this.pnTexto = pnTexto;
}

@Override
public void run() {
//Mientras ningun ejército haya sido derrotado....
while(!heroes.esDerrotado() && !bestias.esDerrotado()) {

//Calculamos el total de turnos, según el ejército más grande
int turnosTotal;
if (heroes.soldados.size() >= bestias.soldados.size())
turnosTotal = heroes.soldados.size();
else
turnosTotal = bestias.soldados.size();

//Comienza una ronda de turnos
for (int turno = 0; turno < turnosTotal; turno++) {
//Seleccionamos combatientes
Heroe heroe = (Heroe) heroes.getSoldado(turno);
Bestia bestia = (Bestia) bestias.getSoldado(turno);
//Comprobamos que ninguno sea null
if (heroe == null && bestia == null)
//¿Ambos son null?Entonces esta ronda de turnos ha terminado
break;
else if (heroe == null) {
//No hay Heroe, Bestia queda en guardia
pnTexto.nuevaLinea(bestia.getNombre() + " queda en guardia");
pausa(500);
}
else if (bestia == null) {
//No hay Bestia, Heroe queda en guardia
pnTexto.nuevaLinea(heroe.getNombre() + " queda en guardia");
pausa(500);
}
else {
//Ninguno es null, comienza el combate
pnTexto.nuevaLinea("Lucha entre " + heroe + " y " + bestia);
pausa(250);
//Turno heroe
pnTexto.nuevaLinea("Turno de " + heroe.getNombre());
pausa(250);
pnTexto.nuevaLinea(heroe.atacar(bestia));
pnTexto.nuevaLinea("Datos Actualizados de " + bestia);
pausa(1000);
if (bestia.estaMuerto()) {
pnTexto.nuevaLinea(bestia.getNombre() + " ha muerto.");
pausa(1000);
}
else {
//Turno bestia
pnTexto.nuevaLinea("Turno de " + bestia.getNombre());
pausa(250);
pnTexto.nuevaLinea(bestia.atacar(heroe));
pnTexto.nuevaLinea("Datos Actualizados de " + heroe);
pausa(1000);
if (heroe.estaMuerto()) {
pnTexto.nuevaLinea(heroe.getNombre() + " ha muerto.");
pausa(1000);
}
}
}
//Turno combate finalizado, ejercitos actualizan sus filas
heroes.comprobarEjercito();
bestias.comprobarEjercito();
//Y se inicia el siguiente turno
}
}

//Las rondas de turnos han finalizado porque algún ejército ha sido derrotado. Comprobamos
if (heroes.esDerrotado())
pnTexto.nuevaLinea("Han ganado las Bestias. Soldados restantes: " + bestias.soldados.size());
else
pnTexto.nuevaLinea("Han ganado los Heroes. Soldados restantes: " + heroes.soldados.size());
}

private void pausa(long milis) {
try {
sleep(milis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}

Hay otro cambio importante aquí. Recuerda que dije que algunos mensajes en pantalla, venían del método atacar de las clases Soldado, por ejemplo:
Código: [Seleccionar]
@Override
public void atacar(Soldado enemigo) {
if (enemigo instanceof Orcos) {
//Regla específica cuando un Elfo ataca un Orco
Random dado = new Random();
int tirada1 = dado.nextInt(101);
int tirada2 = dado.nextInt(101);
System.out.println("Primer dado: " + tirada1);
System.out.println("Segundo dado: " + tirada2);
int maximo =  Math.max(tirada1, tirada2);
System.out.println("*****¡¡El odio élfico hacia los Orcos incrementa el ataque en 1.5x!!*****");
maximo *= 1.5;
System.out.println("Valor de ataque resultante: " + maximo);
enemigo.recibirAtaque(maximo);

}
else //Si no es Orco, se aplica la regla general de los Heroes
super.atacar(enemigo);
}

Estos mensajes se lanzan a la consola durante la ejecución de la "batalla"_
Citar
               else {
                  //Turno bestia
                  System.out.println("Turno de " + bestia.getNombre());
                  bestia.atacar(heroe);
                  System.out.println("Datos Actualizados de " + heroe);

Nosotros hemos reconducido los System.out de la clase Batalla para que ahora salgan por el area de texto, pero estos no los tenemos controlados porque provienen de otras clases...
¿Cómo hacemos para tener control sobre ellos?

Pues vamos a tener que cambiar los métodos atacar() de las clases Soldado, para que en lugar de que hagan System.out por su cuenta, nos retornen esos mensajes como String, y así podamos reconducirlos para que vayan al JTextArea.

Esta "reconducción", ya la he puesto en el código de la clase BatallaHilo que he puesto antes:
Citar
               else {
                  //Turno bestia
                  pnTexto.nuevaLinea("Turno de " + bestia.getNombre());
                  pausa(250);
                  pnTexto.nuevaLinea(bestia.atacar(heroe));
                  pnTexto.nuevaLinea("Datos Actualizados de " + heroe);

Pero para que funcione, hay que modificar las clases Soldado. Comenzando por la clase madre. Aquí pusimos un método abstracto de tipo void para que las clases hijas lo sobreesribiesen a su manera cada una.
Ya no será void, ahora retornará un String
Clase Soldado
Citar
   //Este método lo han de sobreescribir Heroe y Bestia, porque será distinto para cada uno
   public abstract String atacar(Soldado enemigo);

Las siguientes clases hijas, ya no harán System.out. Ahora retornarán los mensajes en un String.

Clase Heroe
Código: [Seleccionar]
@Override
public String atacar(Soldado enemigo) {
// El ataque será el mejor lanzamiento entre dos dados de 0 a 100
Random dado = new Random();
int tirada1 = dado.nextInt(101);
int tirada2 = dado.nextInt(101);
//System.out.println("Primer dado: " + tirada1);
//System.out.println("Segundo dado: " + tirada2);
int maximo =  Math.max(tirada1, tirada2);
enemigo.recibirAtaque(maximo);

return "Primer dado: " + tirada1 + "\n" + "Segundo dado: " + tirada2;
}

Clase Bestia
Código: [Seleccionar]
@Override
public String atacar(Soldado enemigo) {
//Único lanzamiento de un dado entre 0 y 90
Random dado = new Random();
int tirada = dado.nextInt(91);
//System.out.println("Resultado del dado es: " + tirada);
enemigo.recibirAtaque(tirada);
return "Resultado del dado es: " + tirada;
}


La clase Elfos, es la única que tiene una versión propia de este método por aquello de que queríamos un ataque especial cuando luchaba con Orcos.
También ha de ser "reconducido":
Código: [Seleccionar]
@Override
public String atacar(Soldado enemigo) {
if (enemigo instanceof Orcos) {
//Regla específica cuando un Elfo ataca un Orco
Random dado = new Random();
int tirada1 = dado.nextInt(101);
int tirada2 = dado.nextInt(101);
//System.out.println("Primer dado: " + tirada1);
//System.out.println("Segundo dado: " + tirada2);
int maximo =  Math.max(tirada1, tirada2);
//System.out.println("*****¡¡El odio élfico hacia los Orcos incrementa el ataque en 1.5x!!*****");
maximo *= 1.5;
//System.out.println("Valor de ataque resultante: " + maximo);
enemigo.recibirAtaque(maximo);

return "Primer dado: " + tirada1 + "\n" + "Segundo dado: " + tirada2 + "\n"
+ "*****¡¡El odio élfico hacia los Orcos incrementa el ataque en 1.5x!!*****\n"
+ "Valor de ataque resultante: " + maximo;
}
else //Si no es Orco, se aplica la regla general de los Heroes
return super.atacar(enemigo);
}


Vale, tenemos un nuevo panel con area de texto y una renovada clase Batalla que ahora es un hilo que publicará mensajes en el area de texto.

Ahora nos vamos a la clase principal JFrame, porque tenemos que encajar este panel en la interfaz y escribir el ActionListener para el botón de "Luchar".
Este ActionListener lo que hará será poner en marcha el hilo de batalla.

Resalto en azul los cambios:
Citar
public class BatallaRPG extends JFrame {
   
   //Modelo
   private Ejercito bestias;
   private Ejercito heroes;
   
   //Vista
   private PanelCrearSoldado crearHeroes;
   private PanelCrearSoldado crearBestias;
   private PanelTexto pnTexto;
   
   public BatallaRPG() {
      bestias = new Ejercito();
      heroes = new Ejercito();
      reclutar();
      //Este panel referenciará los Heroes
      crearHeroes = new PanelCrearSoldado("Heroes", new String[] {"Elfo", "Humano", "Hobbit"}, heroes);
      //Este refenciará a la Bestias
      crearBestias = new PanelCrearSoldado("Bestias", new String[] {"Trasgo", "Orco"}, bestias);
      
      pnTexto = new PanelTexto();
      pnTexto.setAccionBotonLuchar(new AccionBotonLuchar());

      
      JPanel pnSuperior = new JPanel();
      pnSuperior.add(crearHeroes);
      pnSuperior.add(crearBestias);
      
      JPanel pnInferior = new JPanel();
      pnInferior.add(pnTexto);
      
      setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
      add(pnSuperior);
      add(pnTexto);

      
      setTitle("Batalla RPG");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      pack();
      setLocationRelativeTo(null);
      setVisible(true);
   }
   
   private class AccionBotonLuchar implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         BatallaHilo batalla = new BatallaHilo(heroes, bestias, pnTexto);
         batalla.start();
      }
   }


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

Y con todo esto, ya tenemos un JTextArea que muestra los vaivenes de la batalla.



Hay una pega, el JTextArea no muestra directamente las últimas lineas que se añaden, tenemos que estar haciendo scroll todo el rato para ver los últimos mensajes.

No se si este comportamiento se puede cambiar, lo investigaré.

Pregunta si algo no ha quedado claro, o si sientes que te has perdido..., ya imagino que no esperabas tener que hacer taaaaantos cambios

282
Sí.
Debería bastar con crear un botón en BatallaRPG y en su ActionListener dar comienzo a la batalla invocando al método de la clase Batalla:
Código: [Seleccionar]
btLuchar = new JButton("¡Luchar!");
btLuchar.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Batalla.batallar(heroes, bestias);
}
});

283
Que casualidad...
Mientras escribías tu mensaje, estaba yo escribiendo la explicación de mis acciones.

Es genial que lo intentes, y te falle y no funcione... porque así es como se aprende...

Al eliminar, tienes primero que identificar cuál Soldado ha sido seleccionado en el JList.

El JList es capaz de darte el objeto Soldado elegido, este objeto se lo pasas al ArrayList para que lo borre de su lista, pero hay otro pequeño problema.

Y el problema es que el ArrayList, por sí solo, no sabe como comparar el objeto que tú le vas a pasar con los que tiene listados, para determinar cuál coincide.

Es decir, ¿Cuándo dos Soldados son iguales?
¿Si tienen la misma vida?¿El mismo nombre? ¿El mismo nombre, vida y armadura?....

En principio nos va a bastar cuando tenga el mismo nombre.
Si en la lista hemos elegido el soldado Gandalf, pues queremos que del ArrayList se borre también el objeto Soldado llamado Gandalf.

Pero claro, el ArrayList no sabe si lo que importa para decidir si dos objetos coinciden es el nombre, o la vida, o todos los atributos...

Para que el ArrayList pueda saberlo, necesitamos "enseñar" a los objetos de la clase Soldado a distinguirse unos de otros, o dicho de otro modo, a que sepan decir cuándo dos objetos Soldado son "iguales" y cuando no.

Esto lo hacemos sobreescribiendo el método equals() en la clase Soldado, y ahí vamos a establecer que dos objetos Soldado son iguales cuando coincidan sus nombres:
Código: [Seleccionar]
@Override
public boolean equals(Object obj) {
if (obj instanceof Soldado) {
Soldado otroSoldado = (Soldado) obj;
return nombre.equals(otroSoldado.getNombre());//Si los nombres coinciden, retorna true
}
else
return false;
}
Ahora, dos Soldados pueden compararse y dictaminar si son equivalentes o no.


Gracias a este paso previo, ahora veremos que la acción para el botón "Eliminar" va a requerir muy poco código.
Esta acción lo que hará será recoger el Soldado seleccionado en el JList.
Si no hay ninguno seleccionado, se lanzará un mensaje al usuario.
Y si hay uno seleccionado, simplemente se lo pasaremos al método remove() del ArrayList del Ejercito para que lo elimine y luego actualizamos el JList, donde ya no saldrá el soldado eliminado.

Código: [Seleccionar]
private class AccionEliminar implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
Soldado seleccionado = lista.getSelectedValue();
if (seleccionado == null)
JOptionPane.showMessageDialog(null, "Ha de seleccionar un Soldado");
else {
ejercito.soldados.remove(seleccionado);//Eliminamos del ArrayList
actualizarLista();
}
}
}

Ese método remove(), utilizará internamente el equals() de la clase Soldado para encontrar en su lista el Soldado que es igual al que le hemos pasado (que tiene el mismo nombre) y lo eliminará.
Si no hubieramos sobreescrito el equals(), no nos habría funcionado el remove(), ya que el ArrayList por si mismo, no sabe discernir cuándo dos Soldados son iguales, ya que esa "igualdad" en realidad será según las reglas que decida el programador.


Ahora quedan los botones "subir" y "bajar". Los explico también, pero de nuevo recomiendo que primero intentes tú resolverlos.
Mi primer impulso era escribir dos acciones, una para cada botón, pero luego pensé que ambas acciones iban a ser prácticamente idénticas, así que mejor buscar la forma de escribir una única acción que pueda adaptarse a ambos botones.

La acción de estos botones va a consistir en que el usuario escoge un soldado y lo mueve arriba o abajo.
Mover arriba supone restar -1 a la posición actual del soldado elegido. Si está en posición 5, pasa a la 4.
Bajar supone sumar +1, si está en la 5, pasa a la 6.

Ese -1 ó +1 es la única diferencia entre ambas acciones, así que podemos hacer que el ActionListener de estos botones tenga un atributo de tipo int, llamado "desplazamiento" y que por constructor le pasemos un -1 para el botón "subir" y un +1 para el botón "bajar".
Así la misma acción, se adapta a ambos botones.

Recordemos que el "desplazamiento" no es en el JList donde realmente importa, se ha de hacer en el ArrayList y ya luego el JList lo reflejará en pantalla.

Para hacer este cambio en el ArrayList, lo que hago es recoger el índice que ocupa en el JList el Soldado seleccionado (que es el mismo indice que ocupa en el ArrayList) y además recojo el objeto Soldado seleccionado.

Luego, aplicando el "desplazamiento" (-1 ó +1) recojo, del ArrayList, el soldado que ha de intercambiarse y su índice.
Y para hacer el intercambio, "seteo" en el ArrayList a ambos soldados de nuevo, pero a cada uno le pongo el indice del otro.
Y así quedan intercambiados.
Luego actualizo el JList, y listo.
Código: [Seleccionar]
private class AccionSubirBajar implements ActionListener {

private int desplazamiento; //-1 para subir, +1 para bajar

public AccionSubirBajar(int desplazamiento) {
this.desplazamiento = desplazamiento;
}

@Override
public void actionPerformed(ActionEvent e) {
//Soldado seleccionado en JList
Soldado seleccionado = lista.getSelectedValue();
if (seleccionado == null)
JOptionPane.showMessageDialog(null, "Ha de seleccionar un Soldado");
else {
//Indice de soldado seleccionado, es igual en ambas listas
int indiceSeleccionado = lista.getSelectedIndex();
//Indice del soldado para intercambiar, puede que sea uno anterior o uno posterior
int indiceIntercambiar = indiceSeleccionado + desplazamiento;
//Buscamos en el ArrayList, el soldado para intercambiar
Soldado intercambiar = ejercito.getSoldado(indiceIntercambiar);

//Si intercambiar fuese null, es que el soldado seleccionado no se puede intercambiar
//Por ejemplo, si intentamos subir el soldado que ya está arriba del todo.
if (intercambiar != null) {
//Seteamos los soldados, intercambiando los indices
ejercito.soldados.set(indiceSeleccionado, intercambiar);
ejercito.soldados.set(indiceIntercambiar, seleccionado);
actualizarLista();
}
}
}

}

Y ya tengo las acciones para los tres botones.
Solo tengo que añadírselas, teniendo cuidado de indicar -1 en el constructor para el botón "subir" y +1 para el botón "bajar"
Todo esto lo haremos en la clase PanelLista

Citar
   public PanelLista(String titulo, Ejercito ejercito) {
      this.ejercito = ejercito;
      lista = new JList<Soldado>();
      lista.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
      modeloLista = new DefaultListModel<Soldado>();
      lista.setModel(modeloLista);
      btSubir = new JButton("Subir");
      btSubir.addActionListener(new AccionSubirBajar(-1));
      btBajar = new JButton("Bajar");
      btBajar.addActionListener(new AccionSubirBajar(1));
      btEliminar = new JButton("Eliminar");
      btEliminar.addActionListener(new AccionEliminar());

284
Vamos a crear los paneles inferiores.
Como antes, mediante una única clase, se pueden crear ambos paneles.

Código: [Seleccionar]
public class PanelLista extends JPanel {

private JList<Soldado> lista;
private DefaultListModel<Soldado> modeloLista;
private JButton btSubir;
private JButton btBajar;
private JButton btEliminar;

public PanelLista(String titulo) {
lista = new JList<Soldado>();
lista.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
modeloLista = new DefaultListModel<Soldado>();
lista.setModel(modeloLista);
btSubir = new JButton("Subir");
btBajar = new JButton("Bajar");
btEliminar = new JButton("Subir");

setLayout(new BorderLayout());
JScrollPane scrollLista = new JScrollPane();
scrollLista.setViewportView(lista);
scrollLista.setBorder(BorderFactory.createTitledBorder(null, titulo));
add(scrollLista, BorderLayout.CENTER);

JPanel pnBotones = new JPanel();
pnBotones.add(btSubir);
pnBotones.add(btBajar);
pnBotones.add(btEliminar);
add(pnBotones, BorderLayout.SOUTH);
}

}

Bien, ya tendríamos el panel con la lista. Ahora toca ver donde lo colocamos.

Pensando en el problema de cómo hacer que el panel con JList también tenga acceso a los ejercitos..., me han pasado por la cabeza varias formas de hacerlo, todas ellas correctas, pero a ver cuál es la que requiere menos código y/o resulta menos difícil de entender.

Y entonces se me ha ocurrido que este panel con la lista, aunque sea una clase escrita a parte, la podemos integrar directamente como un componente más del panel de creación de soldados.
Así de forma sencilla, podemos pasarle copia de la referencia de los ejercitos, y no habrá que añadir nuevo código en la clase JFrame.


Así que a PanelLista, la clase que acabamos de escribir, le incluimos atributo y referencia a un ejercito

Citar
public class PanelLista extends JPanel {
   
   private JList<Soldado> lista;
   private DefaultListModel<Soldado> modeloLista;
   private JButton btSubir;
   private JButton btBajar;
   private JButton btEliminar;
   
   private Ejercito ejercito;
   
   public PanelLista(String titulo, Ejercito ejercito) {
      this.ejercito = ejercito;
      lista = new JList<Soldado>();
      lista.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
      modeloLista = new DefaultListModel<Soldado>();
      lista.setModel(modeloLista);
      btSubir = new JButton("Subir");
      btBajar = new JButton("Bajar");
      btEliminar = new JButton("Eliminar");
      
      setLayout(new BorderLayout());
      JScrollPane scrollLista = new JScrollPane();
      scrollLista.setViewportView(lista);
      scrollLista.setBorder(BorderFactory.createTitledBorder(null, titulo));
      add(scrollLista, BorderLayout.CENTER);
      
      JPanel pnBotones = new JPanel();
      pnBotones.add(btSubir);
      pnBotones.add(btBajar);
      pnBotones.add(btEliminar);
      add(pnBotones, BorderLayout.SOUTH);
   }

}

Y en la clase PanelCrearSoldado, añadimos el panel de lista a los atributos como un componente más, le pasamos la referencia por constructor y lo colocamos debajo de las "cajas" apiladas en la interfaz.

Citar
public class PanelCrearSoldado extends JPanel {
   
   private JTextField jtNombre;
   private JComboBox<String> jcTipo;
   private JTextField jtVida;
   private JTextField jtArmadura;
   private JButton btAnadir;
   
   //Atributo para referenciar alguno de los ejercitos de la clase main
   private Ejercito ejercito;
   
   //Panel con la lista de soldados
   private PanelLista lista;

   
   public PanelCrearSoldado(String titulo, String[] tipos, Ejercito ejercito) {
      //Inicializamos componentes
      jtNombre = new JTextField();
      jcTipo = new JComboBox<String>(tipos);
      jtVida = new JTextField();
      jtArmadura = new JTextField();
      btAnadir = new JButton("Añadir");
      btAnadir.addActionListener(new AccionCrearSoldado());
      
      this.ejercito = ejercito; //Ejercito referenciado
      
      lista = new PanelLista(titulo, ejercito); //Pasamos titulo de borde y referencia a ejercito
      
      //Layout de "cajas" verticales
      setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
      
      /*
       * Cada "caja" apilada verticalmente será un panel
       * de clase PanelConLabel
       */
      add(new PanelConLabel("Nombre:", jtNombre));
      add(new PanelConLabel("Tipo:", jcTipo));
      add(new PanelConLabel("Vida:", jtVida));
      add(new PanelConLabel("Armadura:", jtArmadura));
      
      //Boton añadir, le damos un panel propio para que quede mejor centrado
      JPanel pnAnadir = new JPanel();
      pnAnadir.add(btAnadir);
      add(pnAnadir);
      
      //Colocamos el panel lista debajo de todo
      add(lista);

      
      //Combinamos dos bordes, uno titulado y otro vacío para crear algo de relleno
      setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createEmptyBorder(15, 15, 15, 15),
            BorderFactory.createTitledBorder(titulo)));
      
   }
   
   private class PanelConLabel extends JPanel {
      
      public PanelConLabel(String texto, JComponent componente) {
         //Layout tipo grilla, será una fila con dos columnas
         setLayout(new GridLayout(1,2));
         //En la primera columna, la etiqueta
         add(new JLabel(texto));
         //En la segunda columna, el componente que acompaña la etiqueta
         add(componente);
         //"Inflamos" el panel con algo de borde vacío
         setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
      }
   }
   
   private class AccionCrearSoldado implements ActionListener {

      @Override
      public void actionPerformed(ActionEvent e) {
         //Recogemos datos
         String nombre = jtNombre.getText();
         String tipo = (String) jcTipo.getSelectedItem();
         int vida = Integer.parseInt(jtVida.getText());
         int armadura = Integer.parseInt(jtArmadura.getText());
         
         //Creamos nuevo soldado según tipo
         switch(tipo) {
         case "Elfo":
            ejercito.reclutarSoldado(new Elfos(nombre, vida, armadura));
            break;
         case "Humano":
            ejercito.reclutarSoldado(new Humano(nombre, vida, armadura));
            break;
         case "Hobbit":
            ejercito.reclutarSoldado(new Hobbits(nombre, vida, armadura));
            break;
         case "Trasgo":
            ejercito.reclutarSoldado(new Trasgo(nombre, vida, armadura));
            break;
         case "Orco":
            ejercito.reclutarSoldado(new Orcos(nombre, vida, armadura));
            break;
         }
         //Limpiamos campos
         jtNombre.setText(null);
         jcTipo.setSelectedIndex(0);
         jtVida.setText(null);
         jtArmadura.setText(null);
         
         //Confirmamos en consola la creación
         System.out.println("Nuevo soldado reclutado");         
      }
   }

}


Y si ahora ejecutamos el programa, voilá, ya tenemos la interfaz prácticamente terminada. Falta el botón de "¡Lucha!", que aún no lo necesitamos (y el botón "Eliminar" tiene mal el texto, luego lo corrijo)


Tal vez no queda guay que el borde titulado que antes rodeaba el panel de creación, ahora también está rodeando el panel de la lista...., pero esto es un detalle estético del que yo me preocuparía al final, cuando el programa ya estuviera funcionando bien.

Porque ahora viene eso, lo difícil, hacer que todo funcione...

A ver, necesitamos que al agregar soldados, aparezcan en la lista.

Podemos hacer un método público en la clase PanelLista que renueve los elementos de la lista según lo que contenga el ArrayList del ejercito que tengamos referenciado.

Código: [Seleccionar]
public void actualizarLista() {
modeloLista.clear();
for (Soldado sold: ejercito.soldados) //Ejercito nos proporciona el ArrayList de Soldados
modeloLista.addElement(sold);

lista.setModel(modeloLista);
}

Y en la clase PanelCrearSoldado, en el ActionListener de su botón "Añadir", en lugar de lanzar un mensaje en consola, ahora lo que hacemos es invocar al método actualizarLista()
Citar
   private class AccionCrearSoldado implements ActionListener {

      @Override
      public void actionPerformed(ActionEvent e) {
         //Recogemos datos
         String nombre = jtNombre.getText();
         String tipo = (String) jcTipo.getSelectedItem();
         int vida = Integer.parseInt(jtVida.getText());
         int armadura = Integer.parseInt(jtArmadura.getText());
         
         //Creamos nuevo soldado según tipo
         switch(tipo) {
         case "Elfo":
            ejercito.reclutarSoldado(new Elfos(nombre, vida, armadura));
            break;
         case "Humano":
            ejercito.reclutarSoldado(new Humano(nombre, vida, armadura));
            break;
         case "Hobbit":
            ejercito.reclutarSoldado(new Hobbits(nombre, vida, armadura));
            break;
         case "Trasgo":
            ejercito.reclutarSoldado(new Trasgo(nombre, vida, armadura));
            break;
         case "Orco":
            ejercito.reclutarSoldado(new Orcos(nombre, vida, armadura));
            break;
         }
         //Limpiamos campos
         jtNombre.setText(null);
         jcTipo.setSelectedIndex(0);
         jtVida.setText(null);
         jtArmadura.setText(null);
         
         //Actualizamos lista
         lista.actualizarLista();   
      
      }
   }

Y ahora, cada vez que creamos un soldado, la lista los va mostrando.


En el método actualizarLista(), puede parecer un poco bruto que cada vez que se añada un elemento al ArrayList, me cargo el contenido del JList por completo y vuelvo a añadirlos todos, en lugar de simplemente añadir el último soldado creado, que sería más óptimo.

Lo he hecho así porque posiblemente, si luego queremos eliminar elementos de la lista, y cambiar el orden (que por lo tanto, habrá que cambiarlo también en el ArrayList de los ejercitos) en esos casos será más cómodo actualizar la lista por "las bravas", la borramos y la escribimos de nuevo, siempre después de haber hecho los cambios previamente en el ArrayList.

Así que ya tenemos ese método disponible para esas funcionalidades.

Curiosamente, para agregar nuevos soldados es precisamente cuándo no hace falta hacerlo por "las bravas" je je. Luego más adelante podemos crear otro método menos "agresivo" para ese caso, cuando el programa este terminado y queramos hacer algunas optimizaciones.

Pregunta si algo no te ha quedado claro de estos dos últimos mensajes. Si decides continuar con este código que he ido escribiendo, intenta tú ahora hacer los ActionListener para los botones "Subir", "Bajar" y "Eliminar"

Recuerda que los cambios que hagamos en el JList, han de reflejarse también en los ArrayList de los ejercitos.
Porque luego, cuando comience la "batalla", los Soldados que pelearan serán los que estén en los ArrayList, no en los JList, así que han de estar sincronizadas ambas listas: mismos soldados y en el mismo orden.

285
Es normal bloquearse  al principio ;)
Y también seguir caminos que llevan a callejones sin salida, pero no te preocupes, forma parte del proceso de aprendizaje.

Lo ideal es centrarte primero en crear la Vista, sin preocuparte demasiado por el Modelo.
Es decir, haz una interfaz con sus campos y botones, que de momento, no van a tener ninguna función.

Luego ya irás integrando el Modelo. Y sí, puede que durante ese proceso veas la necesidad de reescribir o desechar parte del código escrito para la Vista. Pero así va esto.

A ver, voy a empezar un proyecto de cero.
En el diseño que propones, tanto para la parte de arriba como para la de abajo, yo crearía dos paneles a partir de una única clase.
Lo señalado en rojo serían dos paneles, pero de una misma clase.
Y lo mismo para lo señalado en verde.


Veamos la clase para los paneles superiores.
En lo que respecta a la Vista, entre ambos paneles solo cambia el titulo del borde del panel y las opciones del JComboBox. Así que estos datos se pueden indicar por el constructor

Para maquetar los componentes, puedes usar el/los layouts que tú prefieras.

Yo (de momento) creo que voy a usar un BoxLayout vertical, donde apilar paneles unos sobre otros.
Estos paneles los haré con una subclase que reciba por constructor el texto para un JLabel y el componente que acompañará

Clase PanelCrearSoldado
Código: [Seleccionar]
public class PanelCrearSoldado extends JPanel {

private JTextField jtNombre;
private JComboBox<String> jcTipo;
private JTextField jtVida;
private JTextField jtArmadura;
private JButton btAnadir;

public PanelCrearSoldado(String titulo, String[] tipos) {
//Inicializamos componentes
jtNombre = new JTextField();
jcTipo = new JComboBox<String>(tipos);
jtVida = new JTextField();
jtArmadura = new JTextField();
btAnadir = new JButton("Añadir");

//Layout de "cajas" verticales
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

/*
* Cada "caja" apilada verticalmente será un panel
* de clase PanelConLabel
*/
add(new PanelConLabel("Nombre:", jtNombre));
add(new PanelConLabel("Tipo:", jcTipo));
add(new PanelConLabel("Vida:", jtVida));
add(new PanelConLabel("Armadura:", jtArmadura));

//Boton añadir
add(btAnadir);

//Combinamos dos bordes, uno titulado y otro vacío para crear algo de relleno
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(15, 15, 15, 15),
BorderFactory.createTitledBorder(titulo)));

}

private class PanelConLabel extends JPanel {

public PanelConLabel(String texto, JComponent componente) {
//Layout tipo grilla, será una fila con dos columnas
setLayout(new GridLayout(1,2));
//En la primera columna, la etiqueta
add(new JLabel(texto));
//En la segunda columna, el componente que acompaña la etiqueta
add(componente);
}
}

}

Estaría bien poder ver cómo ha quedado, así que vamos a crear ahora la clase principal, que será el JFrame que contenga toda la interfaz.
De momento mostraremos solo el panel que hemos desarrollado, a ver que aspecto tiene.
Código: [Seleccionar]
public class BatallaRPG extends JFrame {

private PanelCrearSoldado crearHeroes;

public BatallaRPG() {

crearHeroes = new PanelCrearSoldado("Heroes", new String[] {"Elfo", "Humano", "Hobbit"});

setContentPane(crearHeroes);

setTitle("Batalla RPG");
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 BatallaRPG();
}
});
}
}

Veamos qué se nos dibuja en pantalla:


Bueno, no es una belleza, pero básicamente es el diseño que buscábamos. Necesita arreglillos.
Más separación entre las "cajas" apiladas, podemos hacerlo inflándolas un poco añadiendo algo de borde vacío en su interior.
Y el botón "Añadir" quedará mejor centrado si lo colocamos dentro de su propio panel...

Citar
public class PanelCrearSoldado extends JPanel {
   
   private JTextField jtNombre;
   private JComboBox<String> jcTipo;
   private JTextField jtVida;
   private JTextField jtArmadura;
   private JButton btAnadir;
   
   public PanelCrearSoldado(String titulo, String[] tipos) {
      //Inicializamos componentes
      jtNombre = new JTextField();
      jcTipo = new JComboBox<String>(tipos);
      jtVida = new JTextField();
      jtArmadura = new JTextField();
      btAnadir = new JButton("Añadir");
      
      //Layout de "cajas" verticales
      setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
      
      /*
       * Cada "caja" apilada verticalmente será un panel
       * de clase PanelConLabel
       */
      add(new PanelConLabel("Nombre:", jtNombre));
      add(new PanelConLabel("Tipo:", jcTipo));
      add(new PanelConLabel("Vida:", jtVida));
      add(new PanelConLabel("Armadura:", jtArmadura));
      
      //Boton añadir, le damos un panel propio para que quede mejor centrado
      JPanel pnAnadir = new JPanel();
      pnAnadir.add(btAnadir);
      add(pnAnadir);

      
      //Combinamos dos bordes, uno titulado y otro vacío para crear algo de relleno
      setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createEmptyBorder(15, 15, 15, 15),
            BorderFactory.createTitledBorder(titulo)));
      
   }
   
   private class PanelConLabel extends JPanel {
      
      public PanelConLabel(String texto, JComponent componente) {
         //Layout tipo grilla, será una fila con dos columnas
         setLayout(new GridLayout(1,2));
         //En la primera columna, la etiqueta
         add(new JLabel(texto));
         //En la segunda columna, el componente que acompaña la etiqueta
         add(componente);
         //"Inflamos" el panel con algo de borde vacío
         setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

      }
   }

}

A ver...



Bueno, ya tiene mejor aspecto. Por ahora puede servir para seguir avanzando.
Lo que haremos será poner a su lado un segundo panel, esta vez para crear Bestias.

Para ponerlos juntos, en el JFrame crearemos un "panel superior" donde insertaremos nuestros dos paneles de creación de soldados.

Citar
public class BatallaRPG extends JFrame {
   
   private PanelCrearSoldado crearHeroes;
   private PanelCrearSoldado crearBestias;
   
   public BatallaRPG() {
      
      crearHeroes = new PanelCrearSoldado("Heroes", new String[] {"Elfo", "Humano", "Hobbit"});
      crearBestias = new PanelCrearSoldado("Bestias", new String[] {"Trasgo", "Orco"});
      
      JPanel pnSuperior = new JPanel();
      pnSuperior.add(crearHeroes);
      pnSuperior.add(crearBestias);
      
      setContentPane(pnSuperior);

      
      setTitle("Batalla RPG");
      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 BatallaRPG();   
         }
      });
   }
}

Y de esta manera, con una única clase JPanel, ya tenemos dos paneles idénticos para crear un tipo de soldado u otro.




Bueno, y ahora viene el quid de la cuestión.
¿Dónde se guardan los soldados? ¿Cómo sabrán estos paneles que soldado crear y donde ubicarlos?

Bien, tendremos dos Ejercitos, y estos conviene que se encuentren en la clase principal JFrame, para que su "ámbito" sea lo más amplio posible y los distintos paneles que finalmente compongan la interfaz tengan posibilidad de acceder a ellos.

Así que los añadimos como atributos del JFrame, y los inicializamos en el constructor.
Citar
public class BatallaRPG extends JFrame {
   
   //Modelo
   private Ejercito bestias;
   private Ejercito heroes;

   
   //Vista
   private PanelCrearSoldado crearHeroes;
   private PanelCrearSoldado crearBestias;
   
   public BatallaRPG() {
      bestias = new Ejercito();
      heroes = new Ejercito();

      crearHeroes = new PanelCrearSoldado("Heroes", new String[] {"Elfo", "Humano", "Hobbit"});
      crearBestias = new PanelCrearSoldado("Bestias", new String[] {"Trasgo", "Orco"});
      
      JPanel pnSuperior = new JPanel();
      pnSuperior.add(crearHeroes);
      pnSuperior.add(crearBestias);
      
      setContentPane(pnSuperior);
      
      setTitle("Batalla RPG");
      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 BatallaRPG();   
         }
      });
   }
}

Ahora necesitamos que los paneles de creación de soldados, tengan algún tipo de conexión con estos ejércitos para poder agregarles soldados.

Una forma, sería dotar a estos paneles de una referencia a estos ejércitos. Como cada panel va a interactuar con un único ejercito, le añadimos a su clase un ejercito como atributo, y recibirá por constructor la referencia de uno de los ejércitos declarados en la clase principal.

Ya de paso, desarrollamos un ActionListener para que el botón "Añadir" comience a funcionar.
Esta acción ha de recuperar los datos de los campos, evaluar que tipo de soldado se está creando y añadirlo al ejercito que tenga referenciado.
De momento, podemos informar por consola de que hay un nuevo recluta.

Citar
public class PanelCrearSoldado extends JPanel {
   
   private JTextField jtNombre;
   private JComboBox<String> jcTipo;
   private JTextField jtVida;
   private JTextField jtArmadura;
   private JButton btAnadir;
   
   //Atributo para referenciar alguno de los ejercitos de la clase main
   private Ejercito ejercito;

   
   public PanelCrearSoldado(String titulo, String[] tipos, Ejercito ejercito) {
      //Inicializamos componentes
      jtNombre = new JTextField();
      jcTipo = new JComboBox<String>(tipos);
      jtVida = new JTextField();
      jtArmadura = new JTextField();
      btAnadir = new JButton("Añadir");
      btAnadir.addActionListener(new AccionCrearSoldado());
      
      this.ejercito = ejercito; //Ejercito referenciado
      
      //Layout de "cajas" verticales
      setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
      
      /*
       * Cada "caja" apilada verticalmente será un panel
       * de clase PanelConLabel
       */
      add(new PanelConLabel("Nombre:", jtNombre));
      add(new PanelConLabel("Tipo:", jcTipo));
      add(new PanelConLabel("Vida:", jtVida));
      add(new PanelConLabel("Armadura:", jtArmadura));
      
      //Boton añadir, le damos un panel propio para que quede mejor centrado
      JPanel pnAnadir = new JPanel();
      pnAnadir.add(btAnadir);
      add(pnAnadir);
      
      //Combinamos dos bordes, uno titulado y otro vacío para crear algo de relleno
      setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createEmptyBorder(15, 15, 15, 15),
            BorderFactory.createTitledBorder(titulo)));
      
   }
   
   private class PanelConLabel extends JPanel {
      
      public PanelConLabel(String texto, JComponent componente) {
         //Layout tipo grilla, será una fila con dos columnas
         setLayout(new GridLayout(1,2));
         //En la primera columna, la etiqueta
         add(new JLabel(texto));
         //En la segunda columna, el componente que acompaña la etiqueta
         add(componente);
         //"Inflamos" el panel con algo de borde vacío
         setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
      }
   }
   
   private class AccionCrearSoldado implements ActionListener {

      @Override
      public void actionPerformed(ActionEvent e) {
         //Recogemos datos
         String nombre = jtNombre.getText();
         String tipo = (String) jcTipo.getSelectedItem();
         int vida = Integer.parseInt(jtVida.getText());
         int armadura = Integer.parseInt(jtArmadura.getText());
         
         //Creamos nuevo soldado según tipo
         switch(tipo) {
         case "Elfo":
            ejercito.reclutarSoldado(new Elfos(nombre, vida, armadura));
            break;
         case "Humano":
            ejercito.reclutarSoldado(new Humano(nombre, vida, armadura));
            break;
         case "Hobbit":
            ejercito.reclutarSoldado(new Hobbits(nombre, vida, armadura));
            break;
         case "Trasgo":
            ejercito.reclutarSoldado(new Trasgo(nombre, vida, armadura));
            break;
         case "Orco":
            ejercito.reclutarSoldado(new Orcos(nombre, vida, armadura));
            break;
         }
         //Limpiamos campos
         jtNombre.setText(null);
         jcTipo.setSelectedIndex(0);
         jtVida.setText(null);
         jtArmadura.setText(null);
         
         //Confirmamos en consola la creación
         System.out.println("Nuevo soldado reclutado");         
      }

   }

}

Ahora en la clase JFrame, ya podemos pasarles las referencias a estos paneles
Citar
public class BatallaRPG extends JFrame {
   
   //Modelo
   private Ejercito bestias;
   private Ejercito heroes;
   
   //Vista
   private PanelCrearSoldado crearHeroes;
   private PanelCrearSoldado crearBestias;
   
   public BatallaRPG() {
      bestias = new Ejercito();
      heroes = new Ejercito();
      //Este panel referenciará los Heroes
      crearHeroes = new PanelCrearSoldado("Heroes", new String[] {"Elfo", "Humano", "Hobbit"}, heroes);
      //Este refenciará a la Bestias
      crearBestias = new PanelCrearSoldado("Bestias", new String[] {"Trasgo", "Orco"}, bestias);


Y ahora ya podemos crear soldados en los ejércitos.
Parece que todo va por buen camino, pero luego va a venir una dificultad.... :o

Los soldados creados, han de mostrarse en un JList que aún no hemos creado. Este JList, se escribirá en otra clase JPanel.
La idea es que, al pulsar el botón "Añadir" en el panel de creación, se muestre el nuevo soldado en el JList.

Pero, y he aquí la dificultad, el botón "Añadir" y el JList pertenecen a clases diferentes. Desde el ActionListener que hemos escrito en el panel de crear personajes, no podemos actuar sobre el JList. Habrá que buscar, de nuevo, alguna solución para que haya comunicación entre esos paneles.
Pero eso ya lo veremos luego.

286
Coger un código escrito para el "modo consola" y adaptarlo a una GUI, sí, es más complicado de lo que parece, porque el flujo del programa es muy distinto, así como la forma de organizarlo.

Además, no se que herramientas vas a usar para crearlo.
Es decir, en los centros de enseñanza es habitual enseñar Swing creando interfaces directamente con el asistente de Netbeans (o el equivalente para otro IDE), con la opción JFrame Form, donde indicas donde quieres colocar un componente swing y Netbeans te escribe todo el código necesario (y también el innecesario).
Esto permite crear de forma rápida interfaces, pero implica que el programador se desentienda de la estructura del código y en mi modesta opinión (no soy ni maestro, ni profesional ni nada...) luego cuesta más encontrar una forma coherente de combinar y relacionar la Vista (lo que se ve en pantalla, botones, campos, etiquetas...) con el Modelo (lo que no se ve, los ArrayList, variables, métodos, clases, etc..)

Yo las interfaces las hago escribiendo código a mano y es cierto que se requiere más tiempo de aprendizaje conseguir crear interfaces medio decentes..., pero al tener total control sobre el código escrito, luego es más fácil relacionar Vista y Modelo.

No se cuál de estos dos métodos vas a emplear tú, pero en cualquier caso...

...el panel superior, o los paneles superiores (yo uniría dos paneles creados a partir de una misma clase) su función es crear Soldados para los Ejercitos.

El código debería tener en algún sitio dos objetos Ejercitos ya declarados e inicializados al comenzar el programa.
Estos Ejercitos comienza sin Soldados, los cuáles se irán creando con el panel superior y añadiendo al Ejercito correspondiente según si son Heroes o Bestias.

Si el panel superior va a ser creado como clase independiente del resto del programa, necesitamos de algún modo que tenga acceso a esos Ejercitos para que cuando se pulse el botón Añadir pueda agregar Soldados a los Ejercitos.

Una opción es pasar por constructor una referencia a esos Ejercitos, los cuales seguramente vamos a querer tener declarados en la clase JFrame principal.
Así, los cambios que hagamos en los Ejercitos desde la clase del panel superior, se verán reflejados en los Ejercitos declarados en la clase principal.


Otra opción, es escribir el código del ActionListener del botón "Añadir" como una subclase escrita en la clase JFrame principal, donde se tendría acceso a los Ejercitops ahí declarados.
Luego, este ActionListener se lo transferimos al botón del panel superior. Así, aunque este panel superior no tenga referencia o acceso a los Ejercitos, no importará, porque su ActionListener, que es quien recogerá los datos introducidos y creará el nuevo Soldado, si tiene acceso a los Ejercitos.



No se si me estoy explicando bien, a ver si mañana puedo escribir algún ejemplo.

287
OK.

Pues como dije, para los dos paneles superiores en principio bastaría con escribir una única clase JPanel.
Solo cambiará el texto de algún JLabel y que uno será para Heroes y otro para Bestias, que en realidad todos son clase Soldado.

Lo mismo con los paneles inferiores, escribiendo una sola clase podrías crear ambos paneles.

En la parte inferior, quizás se podría añadir otro panel con un JTextArea donde se irían mostrando los textos del combate

288
Mmmmhh.. Recomiendo primero hacer un dibujo, ya sea con Paint o con papel y lápiz, haciendo un boceto aproximado de lo que se quiere conseguir tener en pantalla.
No tiene que ser una obra de arte, bastan unos garabatos que ayuden a visualizar lo que se tiene en mente.

A partir de ahí es más fácil identificar donde será necesario un panel, un botón,...
Que luego sobre la marcha, se van tomando decisiones y quizá se acaba diseñando algo muy distinto a lo dibujado, pero el boceto al menos ya de un punto de partida.

No se cómo tienes pensado diseñarlo, pero es muy posible que puedas escribir una única clase JPanel, de la que crear dos objetos (dos paneles) y que sirva por igual para Heroes y Bestias en lo que respecta a la "Vista".
Lo que cambiará serán los datos (el "Modelo") que le pases a cada panel, es decir, a uno le pasarás Heroes y al otro Bestias

289
Claro, porque esos datos como dije están encapsulados en otros objetos.
La clase Casa no puede acceder directamente a ellos, pero sí puede pedírselos a los objetos(salonCasa y cocinaCasa) que los encapsulan.

Prueba así:
Citar
        System.out.println ("Los principales datos de esta casa son: superficie, " + superficie + " y direccioón, " + direccion + ". Además, podemos decir que el salón de la casa es " + salonCasa.getTipoSalon() + " y hay " + salonCasa.getNumeroDeTelevisores() + " televisores. Por último, vamos a mencionar que la cocina tiene " + cocinaCasa.getNumeroDeFuegos() + " fuegos en la hornalla y que es " + cocinaCasa.getEsIndependiente()+ " su independencia.");

290
Hola.
Respecto al código que has agregado....

Para que la clase Casa pueda mostrar toda la información, como el número de televisores, etc... no es necesario que añadas nuevos atributos, porque en realidad la clase Casa ya dispone de esa información, solo que está encapsulada en otros objetos.
Además, esos atributos "añadidos", aunque se llamen igual, son distintos de los atributos "originales" y no tendrán los mismos valores.

El número de televisores y el tipo de salón, se los podemos solicitar al objeto SalonCasa

Citar
public class Casa {
   
    private double superficie;
    private String direccion;
    private SalonCasa salonCasa;
    private CocinaCasa cocinaCasa;
    private int numeroDeTelevisores;
    private String tipoSalon;

    private boolean esIndependiente;
    private int numeroDeFuegos;

Y el número de fuegos que tiene la cocina y saber si esta es independiente, se lo podemos preguntar al objeto CocinaCasa

Citar
public class Casa {
   
    private double superficie;
    private String direccion;
    private SalonCasa salonCasa;
    private CocinaCasa cocinaCasa;
    private int numeroDeTelevisores;
    private String tipoSalon;
    private boolean esIndependiente;
    private int numeroDeFuegos;

Así que no se necesitan más atributos, es suficiente con estos:

Código: [Seleccionar]
public class Casa {
   
    private double superficie;
    private String direccion;
    private SalonCasa salonCasa;
    private CocinaCasa cocinaCasa;

¿Y cómo hacemos que la clase Casa tenga getters para mostrar esos datos "encapsulados" en SalonCasa y CocinaCasa?

Pues hacemos que los getters de Casa, invoquen a los getters de esos objetos.

Por ejemplo, para que Casa pueda informar del nº de televisores:

Código: [Seleccionar]
public int getNumeroDeTelevisores () {return salonCasa.getNumeroDeTelevisores();}
¿Ves? Un método no tiene por qué retornar siempre el valor de una variable. Puede retornar también el valor que nos retorne otro método.
Así que el getNumeroDeTelevisores() de Casa, retorna lo que resulte de llamar al getNumeroDeTelevisores() de SalonCasa, quien a su vez retorna el valor de su atributo numeroDeTelevisores.
Este último atributo es el válido, el auténtico, el que tiene el valor que nos interesa.

Si añades otro atributo a Casa, aunque tenga el mismo nombre, no tendrá nada que ver con el de SalonCasa y podrían tener valores distintos.

Esto mismo es aplicable a los setters.
Si quisiéramos que la clase Casa pudiera recibir y modificar el número de televisores, lo que haría será llamar al setter de SalonCasa y transferir el valor que ha recibido:
Código: [Seleccionar]
    public void setNumeroDeTelevisores (int valorNumeroDeTelevisores){
        salonCasa.setNumeroDeTelevisores(valorNumeroDeTelevisores);
    }

Espero haberme explicado bien.
Prueba a corregir los otros getters y setters de Casa para que interactúen con los correspondientes getter/setters de sus atributos SalonCasa y CocinaCasa

291
Mejor, pero sigue sin ser necesarios los parámetros recibidos por paréntesis.

Citar
    public Casa (double valorSuperficie, String valorDireccion, SalonCasa valorSalonCasa, CocinaCasa valorCocinaCasa){
        superficie = 0.0;
        direccion = "";
        salonCasa = new SalonCasa ();
        cocinaCasa = new CocinaCasa ();
    }

La mayoría de veces, sí vamos a querer recibir parámetros por los paréntesis del constructor y usarlos para asignarlos a los atributos.
E incluso verás que será habitual tener dos (o más) constructores, uno que no reciba parámetros y otro que sí.

Pero en este ejercicio en concreto, no los vamos a necesitar, por lo que el constructor quedaría así:
Citar
    public Casa(){
        superficie = 0.0;
        direccion = "";
        salonCasa = new SalonCasa();
        cocinaCasa = new CocinaCasa();
    }

Sigue compartiendo tus dudas, espero que aprendas y te diviertas con el curso Java.
Un saludo.

292
Hola y bienvenido.

El constructor de la clase Casa...
Código: [Seleccionar]
    public Casa (double superficieCasa, String direccionCasa, SalonCasa salonCasaCasa, CocinaCasa cocinaCasaCasa){
        superficie = superficieCasa;
        direccion = direccionCasa;
        salonCasa = new SalonCasa ();
        cocinaCasa = new CocinaCasa ();
    }

 ...no cumple exactamente con lo que pide el enunciado:
Citar
Define un constructor para la clase Casa que establezca a unos valores de defecto los atributos simples y que cree nuevos objetos si se trata de atributos objeto.

Es decir, debería recibir valores entre los paréntesis.
Simplemente inicializar la variables primitivas a unos valores "genéricos" por defecto (por ejemplo valor 0 para los datos numéricos y una cadena vacía para los String) e instanciar nuevos objetos para los variables que sean objetos e clase (esta parte sí la has hecho bien).

Y ya luego, para terminar de afinar la clase, completar los getter y setter.

Un saludo.

293
Mmmhh..
Vamos a ver si lo conseguimos.

Así a bote pronto, se me ocurre comenzar una clase Paciente lo más sencilla posible: nombre, apellidos y un int entre 1 y 3 para indicar la prioridad.

Una constante en forma de array de Strings, podría contener los nombres de las tres prioridades.
Así podemos usar el int del atributo "prioridad" para saber cuál es el nombre de prioridad que le corresponde a este Paciente.

Sobreescribimos su método toString() para tener una forma rápida de mostrar los datos en pantalla.

Código: [Seleccionar]
public class Paciente {

private String nombre;
private String apellidos;
private int prioridad;

private final String[] PRIORIDADES;

public Paciente(String nombre, String apellidos, int prioridad) {
this.nombre = nombre;
this.apellidos = apellidos;
//Nos aseguramos que la prioridad solo sea entre 1 y 3
if (prioridad >= 3)
this.prioridad = 3;
else if (prioridad <= 1)
this.prioridad = 1;
else
this.prioridad = 2;
//Nombres de las prioridades
PRIORIDADES = new String[] {"Terapia Intensiva", "Gravedad", "Atención Médica"};
}

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 getPrioridad() {
return PRIORIDADES[prioridad - 1];
}

@Override
public String toString() {
return String.format("\t%-25s\t%s", (nombre + " " + apellidos), getPrioridad());
}

}

Bien, la intención es que luego haya una cola de pacientes y se respete el "orden de prioridad".
Pues deberíamos enseñarle a esta clase como ha de compararse con otros pacientes para determinar quien tiene prioridad o no.
Esto lo facilitamos implementando la interfaz Comparable y a través de ella le enseñaremos a la clase como se ha de comparar, que básicamente será que lo haga en función del orden natural de su atributo prioridad.
Es decir, el 1 irá delante del 2, y este delante del 3.

Apenas hay que añadir 4 líneas para esto:
Código: [Seleccionar]
public class Paciente implements Comparable<Paciente>{

private String nombre;
private String apellidos;
private int prioridad;

private final String[] PRIORIDADES;

public Paciente(String nombre, String apellidos, int prioridad) {
this.nombre = nombre;
this.apellidos = apellidos;
//Nos aseguramos que la prioridad solo sea entre 1 y 3
if (prioridad >= 3)
this.prioridad = 3;
else if (prioridad <= 1)
this.prioridad = 1;
else
this.prioridad = 2;
//Nombres de las prioridades
PRIORIDADES = new String[] {"Terapia Intensiva", "Gravedad", "Atención Médica"};
}

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 getPrioridad() {
return PRIORIDADES[prioridad - 1];
}

@Override
public String toString() {
return String.format("\t%-25s\t%s", (nombre + " " + apellidos), getPrioridad());
}

@Override
public int compareTo(Paciente otroPaciente) {
return Integer.compare(prioridad, otroPaciente.prioridad);
}

}


Ya tenemos una clase Paciente.
Con ellos hay que formar una Cola, así que vamos a crear la clase Cola.

Podemos usar un ArrayList, tiene la ventaja de que podemos añadir todos los pacientes que queramos y gracias a que hemos implementado la interfaz Comparable, podremos mantener el ArrayList en todo momento ordenado según la prioridad.

Como digo, podremos añadir Pacientes sin limite, pero la cola de pacientes real es de solo 10 Pacientes.
Así que para mostrar el listado, lo que haremos será crear un array con los primeros 10 pacientes del ArrayList, que ya estarán ordenados.
Código: [Seleccionar]
import java.util.ArrayList;

public class Cola {

private ArrayList<Paciente> cola;

public Cola() {
cola = new ArrayList<Paciente>();
}

public void addPaciente(Paciente p) {
cola.add(p);
cola.sort(null); //Ordenamos según prioridad de pacientes
}

public Paciente[] getColaPacientes() {
/*
* La cola tendrá un límite de 10 pacientes.
* Da igual cuántos hayan almacenados en el ArrayList,
* la cola "definitiva" será solo de 10 pacientes.
* Así que construiremos un array de hasta 10 pacientes.
* Añadiremos los primeros pacientes que contiene el arraylist
* el cuál ya estará ordenado por prioridades.
*/
Paciente[] pacientes;
if (cola.size() >= 10)
pacientes = new Paciente[10];
else
pacientes = new Paciente[cola.size()];

for (int i = 0; i < pacientes.length; i++)
pacientes[i] = cola.get(i);

return pacientes;
}

}


Pues vamos a ponerlo a prueba.
Una clase con main() para testear.
Creamos un objeto Cola y con Scanner vamos pidiendo datos para crear Pacientes.

Cada Paciente creado, pedimos a la "cola" que nos de la lista de pacientes y la mostramos. Y preguntamos si se quiere seguir añadiendo más pacientes o terminar el programa.

Código: [Seleccionar]
import java.util.Scanner;

public class Test {

public static void main(String[] args) {

Cola colaPacientes = new Cola();
Scanner teclado = new Scanner(System.in);

do {
System.out.println("\n\nNuevo Paciente.");
System.out.print("Nombre: ");
String nombre = teclado.nextLine();
System.out.print("Apellidos: ");
String apellidos = teclado.nextLine();
System.out.print("Prioridad[1-3]: ");
int prioridad = Integer.parseInt(teclado.nextLine());
//Añadimos a la cola
colaPacientes.addPaciente(new Paciente(nombre, apellidos, prioridad));

//Generamos y mostramos lista
Paciente[] lista = colaPacientes.getColaPacientes();
System.out.println("\n\t\tCOLA DE PACIENTES");
System.out.println("\t\t---- -- ---------\n");
System.out.println("\t    NOMBRE\t\t\t  PRIORIDAD");
System.out.println("\t    ------\t\t\t  ---------");
for (Paciente p: lista)
System.out.println(p);

//Preguntamos si queremos continuar
System.out.println("\n\n¿Seguir añadiendo pacientes?(s/n)");

}while(teclado.nextLine().toLowerCase().charAt(0) == 's');

teclado.close();

}

}

Si lo ejecutamos, veremos que la lista se va mostrando en todo momento, correctamente ordenada, desplazando a los de menor prioridad al fondo de la lista y dejándolos fuera cuando ya hay otros 10 pacientes de mayor prioridad que ellos.

Código: [Seleccionar]

Nuevo Paciente.
Nombre: Andres
Apellidos: Lopez
Prioridad[1-3]: 3

COLA DE PACIENTES
---- -- ---------

    NOMBRE   PRIORIDAD
    ------   ---------
Andres Lopez              Atención Médica


¿Seguir añadiendo pacientes?(s/n)
s


Nuevo Paciente.
Nombre: Belinda
Apellidos: Sanchez
Prioridad[1-3]: 2

COLA DE PACIENTES
---- -- ---------

    NOMBRE   PRIORIDAD
    ------   ---------
Belinda Sanchez          Gravedad
Andres Lopez              Atención Médica


¿Seguir añadiendo pacientes?(s/n)
s


Nuevo Paciente.
Nombre: Sara
Apellidos: Perez
Prioridad[1-3]: 3

COLA DE PACIENTES
---- -- ---------

    NOMBRE   PRIORIDAD
    ------   ---------
Belinda Sanchez          Gravedad
Andres Lopez              Atención Médica
Sara Perez                Atención Médica


¿Seguir añadiendo pacientes?(s/n)
s


Nuevo Paciente.
Nombre: Javier
Apellidos: Quesada
Prioridad[1-3]: 1

COLA DE PACIENTES
---- -- ---------

    NOMBRE   PRIORIDAD
    ------   ---------
Javier Quesada            Terapia Intensiva
Belinda Sanchez          Gravedad
Andres Lopez              Atención Médica
Sara Perez                Atención Médica


¿Seguir añadiendo pacientes?(s/n)
s


Nuevo Paciente.
Nombre: Loreto
Apellidos: Lopez
Prioridad[1-3]: 1

COLA DE PACIENTES
---- -- ---------

    NOMBRE   PRIORIDAD
    ------   ---------
Javier Quesada            Terapia Intensiva
Loreto Lopez              Terapia Intensiva
Belinda Sanchez          Gravedad
Andres Lopez              Atención Médica
Sara Perez                Atención Médica


¿Seguir añadiendo pacientes?(s/n)
s


Nuevo Paciente.
Nombre: Sergio
Apellidos: Guasch
Prioridad[1-3]: 2

COLA DE PACIENTES
---- -- ---------

    NOMBRE   PRIORIDAD
    ------   ---------
Javier Quesada            Terapia Intensiva
Loreto Lopez              Terapia Intensiva
Belinda Sanchez          Gravedad
Sergio Guasch            Gravedad
Andres Lopez              Atención Médica
Sara Perez                Atención Médica


¿Seguir añadiendo pacientes?(s/n)
s


Nuevo Paciente.
Nombre: Luis
Apellidos: Pereda
Prioridad[1-3]: 1

COLA DE PACIENTES
---- -- ---------

    NOMBRE   PRIORIDAD
    ------   ---------
Javier Quesada            Terapia Intensiva
Loreto Lopez              Terapia Intensiva
Luis Pereda              Terapia Intensiva
Belinda Sanchez          Gravedad
Sergio Guasch            Gravedad
Andres Lopez              Atención Médica
Sara Perez                Atención Médica


¿Seguir añadiendo pacientes?(s/n)
s


Nuevo Paciente.
Nombre: Laura
Apellidos: Juan
Prioridad[1-3]: 1

COLA DE PACIENTES
---- -- ---------

    NOMBRE   PRIORIDAD
    ------   ---------
Javier Quesada            Terapia Intensiva
Loreto Lopez              Terapia Intensiva
Luis Pereda              Terapia Intensiva
Laura Juan                Terapia Intensiva
Belinda Sanchez          Gravedad
Sergio Guasch            Gravedad
Andres Lopez              Atención Médica
Sara Perez                Atención Médica


¿Seguir añadiendo pacientes?(s/n)
s


Nuevo Paciente.
Nombre: Alicia
Apellidos: Ventura
Prioridad[1-3]: 3

COLA DE PACIENTES
---- -- ---------

    NOMBRE   PRIORIDAD
    ------   ---------
Javier Quesada            Terapia Intensiva
Loreto Lopez              Terapia Intensiva
Luis Pereda              Terapia Intensiva
Laura Juan                Terapia Intensiva
Belinda Sanchez          Gravedad
Sergio Guasch            Gravedad
Andres Lopez              Atención Médica
Sara Perez                Atención Médica
Alicia Ventura            Atención Médica


¿Seguir añadiendo pacientes?(s/n)
s


Nuevo Paciente.
Nombre: Jorge
Apellidos: Morales
Prioridad[1-3]: 2

COLA DE PACIENTES
---- -- ---------

    NOMBRE   PRIORIDAD
    ------   ---------
Javier Quesada            Terapia Intensiva
Loreto Lopez              Terapia Intensiva
Luis Pereda              Terapia Intensiva
Laura Juan                Terapia Intensiva
Belinda Sanchez          Gravedad
Sergio Guasch            Gravedad
Jorge Morales            Gravedad
Andres Lopez              Atención Médica
Sara Perez                Atención Médica
Alicia Ventura            Atención Médica


¿Seguir añadiendo pacientes?(s/n)
s


Nuevo Paciente.
Nombre: Ana
Apellidos: Blanco
Prioridad[1-3]: 1

COLA DE PACIENTES
---- -- ---------

    NOMBRE   PRIORIDAD
    ------   ---------
Javier Quesada            Terapia Intensiva
Loreto Lopez              Terapia Intensiva
Luis Pereda              Terapia Intensiva
Laura Juan                Terapia Intensiva
Ana Blanco                Terapia Intensiva
Belinda Sanchez          Gravedad
Sergio Guasch            Gravedad
Jorge Morales            Gravedad
Andres Lopez              Atención Médica
Sara Perez                Atención Médica


¿Seguir añadiendo pacientes?(s/n)
n

Y con esto parece que ya tenemos al menos la parte lógica del programa.

Revísalo, pregunta lo que no entiendas y dinos si falta algo más por completar.

Un saludo.

294
Mmmh que raro ese mensaje de error.

Si el método está devolviendo un array (o lo que sea), entonces ya no es un "método void".

¿Podemos ver el código completo? En algún sitio ha de haber un error de sintaxis que hace que el compilador considere void un método que no lo es...


Te dejo además un código de ejemplo, donde un método genera y retorna un array de enteros.

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

public class PruebaMetodoArray {

public static void main(String[] args) {

Scanner teclado = new Scanner(System.in);

System.out.print("Cuantos enteros quieres generar?: ");
int cantidad = teclado.nextInt();

int[] generados = arrayAzarEnteros(cantidad);

System.out.println("\nLista de enteros generados:");
for (int entero: generados)
System.out.print(entero + " ");

teclado.close();

}

/*
* Genera un array con tantos números enteros al azar
* como se le indique por argumentos.
*/
public static int[] arrayAzarEnteros(int numEnteros) {
int[] enteros = new int[numEnteros];

Random azar = new Random();

for (int i = 0; i < enteros.length; i++)
enteros[i] = azar.nextInt(100);

return enteros;
}

}

295
Comunidad / Re: Felices fiestas y próspero año nuevo para todos
« en: 24 de Diciembre 2021, 20:07 »
Feliz Navidad a todos los que nos visitan, leen y participan.

Disfruten de estos días.

296
Sí, sin ningún problema.

Los métodos en Java pueden retornar cualquier objeto o dato de tipo primitivo existente.

297
Aprender a programar desde cero / Re: Busco IDE para Go
« en: 14 de Diciembre 2021, 23:50 »
No tengo ni idea de Go.

Pero si me pusiera a estudiarlo, probablemente usaría Goland
Es producto de la casa JetBrains, y suele ser garantía de calidad.

298
Por si sirve de más ayuda....

Primero se necesita una clase "madre", ya que habrán dos clases de Encuestas, pero se han poder guardar juntas en un mismo vector.
Para ello, es necesario poder instanciarlas bajo una misma clase común a ambas, una clase "madre".

Esta clase tendría los atributos comunes a ambas encuestas: edad y sexo.
Podemos declararla abstracta, no es necesario, pero como no vamos a querer instanciar objetos de esta clase "madre", si no de las clases "hijas", es buena costumbre declararla como abstracta.

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

protected int edad;
protected String sexo;

public Encuesta(int edad, String sexo) {
this.edad = edad;
this.sexo = sexo;
}

public int getEdad() {
return edad;
}

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

public String getSexo() {
return sexo;
}

public void setSexo(String sexo) {
this.sexo = sexo;
}

}

La primera clase "hija" puede llamarse Encuesta1 y aporta los atributos propios de este tipo de encuesta.
Además, podemos darle un método estático que se encargue de mostrar las preguntas acordes a esta encuesta y recoger los datos para construir un objeto Encuesta1.
Código: [Seleccionar]
import java.util.Scanner;

public class Encuesta1 extends Encuesta {

private char escolaridad;
private String hoyNoCircula;

public Encuesta1(int edad, String sexo, char escolaridad, String hoyNoCircula) {
super(edad, sexo);
this.escolaridad = escolaridad;
this.hoyNoCircula = hoyNoCircula;
}

public char getEscolaridad() {
return escolaridad;
}

public void setEscolaridad(char escolaridad) {
this.escolaridad = escolaridad;
}

public String getHoyNoCircula() {
return hoyNoCircula;
}

public void setHoyNoCircula(String hoyNoCircula) {
this.hoyNoCircula = hoyNoCircula;
}

public static Encuesta1 hacerEncuesta1() {
Scanner teclado = new Scanner(System.in);
int edad = 0;
while (edad < 20 || edad > 45) {
System.out.print("Introduzca edad(20/55): ");
edad = Integer.parseInt(teclado.nextLine());
}
System.out.print("Introduzca sexo(Hombre/Mujer): ");
String sexo = teclado.nextLine();
System.out.println("Nivel de Escolaridad(P=Primaria, S=Secundaria, B=Bachillerato, L=Licenciatura");
System.out.print("Introduzca nivel: ");
char escolaridad = teclado.nextLine().toUpperCase().charAt(0);
System.out.println("¿A favor del movimiento \"Hoy no Circula\"?(Si/No): ");
String noCircula = teclado.nextLine();

return new Encuesta1(edad, sexo, escolaridad, noCircula);
}

}

Con la otra clase "hija", llamada Encuesta2, seguimos el mismo patrón.
Código: [Seleccionar]
import java.util.Scanner;

public class Encuesta2 extends Encuesta {

private boolean tieneAuto;
private int hoyNoCircula;

public Encuesta2(int edad, String sexo, boolean tieneAuto, int hoyNoCircula) {
super(edad, sexo);
this.tieneAuto = tieneAuto;
this.hoyNoCircula = hoyNoCircula;
}

public boolean tieneAuto() {
return tieneAuto;
}

public void setTieneAuto(boolean tieneAuto) {
this.tieneAuto = tieneAuto;
}

public int getHoyNoCircula() {
return hoyNoCircula;
}

public void setHoyNoCircula(int hoyNoCircula) {
this.hoyNoCircula = hoyNoCircula;
}

public static Encuesta2 hacerEncuesta2() {
Scanner teclado = new Scanner(System.in);
int edad = 0;
while (edad < 20 || edad > 45) {
System.out.print("Introduzca edad(20/55): ");
edad = Integer.parseInt(teclado.nextLine());
}
System.out.print("Introduzca sexo(Hombre/Mujer): ");
String sexo = teclado.nextLine();
System.out.print("¿Tiene auto?(Si/No): ");
boolean tieneAuto = teclado.nextLine().toLowerCase().equals("si");
int noCircula = 0;
while(noCircula < 1 || noCircula > 3) {
System.out.print("¿A favor del movimiento \"Hoy no Circula\"?(1=si/2=no/3=me es indiferente): ");
noCircula = Integer.parseInt(teclado.nextLine());
}

return new Encuesta2(edad, sexo, tieneAuto, noCircula);
}

}

Ya por último, una clase main donde declaramos un vector de clase Encuesta, que aceptará por igual objetos de Encuesta1 y Encuesta2.

El tamaño de este vector lo decide el usuario al comienzo, es decir, nos dirá cuántas encuestas como máximo se podrán realizar.
Con una variable int podemos controlar cuántas encuestas llevamos hechas en cada momento, para así saber donde se ha de guardar cada nueva encuesta y cuándo hay que parar de aceptar nuevas encuestas.

Se mostrará un menú con las 7 opciones y con un switch se llamará a distintos métodos, según la opción escogida.

Lo importante en este ejercicio, es saber distinguir los objetos según si son instancias de Encuesta1 o Encuesta2, teniendo en cuenta que van a estar guardados como Encuesta

Código: [Seleccionar]
import java.util.Scanner;

public class MenuEncuestas {

private static Encuesta[] encuestas;
private static int encuestasHechas = 0;

public static void main(String[] args) {

Scanner teclado = new Scanner(System.in);

System.out.print("¿Máxima cantidad de encuestas?: ");
encuestas = new Encuesta[Integer.parseInt(teclado.nextLine())];

int opcion = 0;
while (opcion != 7) {
System.out.println("\n1.  Agregar encuesta 1");
System.out.println("2.  Agregar encuesta 2");
System.out.println("3.  Mostrar cuantos votaron a favor del no circula");
System.out.println("4.  Mostrar el total de encuestas tipo1 y tipo 2");
System.out.println("5.  Mostrar el total de votantes mujeres en la encuesta tipo 2");
System.out.println("6.  Mostrar cuantos hombres de la encuesta 2 les es indiferente");
System.out.println("7.  Terminar");
opcion = Integer.parseInt(teclado.nextLine());
switch(opcion) {
case 1:
agregarEncuesta1();
break;
case 2:
agregarEncuesta2();
break;
case 3:
cuantosaFavor();
break;
case 4:
totalEncuestasPorTipo();
break;
case 5:
totalMujeresTipo2();
break;
case 6:
hombresTipo2Indiferentes();
break;
case 7:
System.out.println("\nFIN DE PROGRAMA");
break;
default:
System.out.println("\nOpción equivocada...");
}
}
teclado.close();
}

private static void agregarEncuesta1() {
if (encuestasHechas == encuestas.length)
System.out.println("\nNo se admiten más encuestas.");
else {
encuestas[encuestasHechas] = Encuesta1.hacerEncuesta1();
encuestasHechas++;
}
}

private static void agregarEncuesta2() {
if (encuestasHechas == encuestas.length)
System.out.println("\nNo se admiten más encuestas.");
else {
encuestas[encuestasHechas] = Encuesta2.hacerEncuesta2();
encuestasHechas++;
}
}

private static void cuantosaFavor() {
if (encuestasHechas == 0)
System.out.println("\nAún no se ha hecho ninguna encuesta.");
else {
int aFavor = 0;

for (int i = 0; i < encuestasHechas; i++) {
if (encuestas[i] instanceof Encuesta1) {
Encuesta1 encu1 = (Encuesta1) encuestas[i];
if (encu1.getHoyNoCircula().toLowerCase().equals("si"))
aFavor++;
}
else {
Encuesta2 encu2 = (Encuesta2) encuestas[i];
if (encu2.getHoyNoCircula() == 1)
aFavor++;
}
}

System.out.printf("\nDe %d encuestas realizadas, hay %d votos a favor del \"Hoy no Circula\"\n",
encuestasHechas, aFavor);
}
}

private static void totalEncuestasPorTipo() {
if (encuestasHechas == 0)
System.out.println("\nAún no se ha hecho ninguna encuesta.");
else {
int tipo1 = 0, tipo2 = 0;

for (int i = 0; i < encuestasHechas; i++) {
if (encuestas[i] instanceof Encuesta1)
tipo1++;
else
tipo2++;
}

System.out.println("\nTotal encuestas de Tipo 1: " + tipo1);
System.out.println("Total encuestas de Tipo 2: " + tipo2);
}
}

private static void totalMujeresTipo2() {
if (encuestasHechas == 0)
System.out.println("\nAún no se ha hecho ninguna encuesta.");
else {
int mujeres = 0;

for (int i = 0; i < encuestasHechas; i++) {
if (encuestas[i] instanceof Encuesta2) {
Encuesta2 encu2 = (Encuesta2) encuestas[i];
if (encu2.getSexo().toLowerCase().equals("mujer"))
mujeres++;
}
}

System.out.println("\nMujeres encuestadas en el tipo 2: " + mujeres);
}
}

private static void hombresTipo2Indiferentes() {
if (encuestasHechas == 0)
System.out.println("\nAún no se ha hecho ninguna encuesta.");
else {
int hombres = 0;

for (int i = 0; i < encuestasHechas; i++) {
if (encuestas[i] instanceof Encuesta2) {
Encuesta2 encu2 = (Encuesta2) encuestas[i];
if (encu2.getHoyNoCircula() == 3)
hombres++;
}
}

System.out.println("\nHombres indiferentes en el tipo 2: " + hombres);
}
}
}

299
Hola.

No pienses en el ejercicio al completo. Centrate solo en escribir estas dos clases, puedes llamarlas Encuesta1 y Encuesta2 por ejemplo:

Citar
·       En la primera encuesta solicitar la edad, sexo, escolaridad (P=Primaria, S=secundaria, B=Bachillerato, L=Licenciatura) y respuesta sobre la pregunta de la encuesta (sí o no).

·       En la segunda encuesta solicitar la edad, sexo, tiene auto (true o false) y respuesta sobre la pregunta de la encuesta (1=si, 2=no, 3=me es indiferente).

Puesto que se guardarán juntas en un mismo vector, debería ser hijas de una clase Encuesta "madre".

Intenta escribirlas, da igual si no te salen bien, comparte por aquí lo que consigas y te ayudamos a corregirlas o ver en que pueden mejorarse.

Y ya luego se irá viendo las demás cosas que pide el enunciado.

Pero es importante que comiences tú el código.
Saludos.

300
Comunidad / Re: me presento
« en: 15 de Noviembre 2021, 11:23 »
Bienvenido.

Intentaremos ayudarte en lo que podamos.
No dejes de visitar los distintos cursos que hay en la web, alguno podrá resultarte útil.

Un saludo.

Páginas: 1 ... 10 11 12 13 14 [15] 16 17 18 19 20 ... 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".