Autor Tema: Java mostrar muchos botones matriz JButton usando array swing JPanel JLabel  (Leído 12443 veces)

paloma8513

  • Sin experiencia
  • *
  • Mensajes: 2
  • cada dia aprendo mas
    • Ver Perfil
Hola soy nueva en el foro y espero puedan ayudarme, estoy haciendo un programa para la escuela y ya realicé el codigo y hace lo que necesito (funciona bien) pero tengo que repetirlo en 105 botones,  :(  me comentan que con un array puedo hacerlo más rapido y no hacerlo 1 por 1. ¿Podrían ayudarme con eso del array para ver como puedo hacer que se repita 104 veces más...?

Código: [Seleccionar]
public class E1 extends javax.swing.JFrame {
   
String lugar =("");
int ocupados = 0;
int vacios = 35;
int lugares ;

    public E1() {
        initComponents();
       
        jPanel1.setBackground(Color.GREEN);
        rbtn1.addActionListener(new ActionListener(){
           
    public void actionPerformed(ActionEvent e) {
           
        if(rbtn1.isSelected())
            {
            jPanel1.setBackground(Color.BLUE);
            String L1 = lbl1.getText();
            lugar = L1;
            vacios --;
            ocupados ++;
            JOptionPane.showMessageDialog (null,"Selecciono el "+ L1 );
            }
        else{
            jPanel1.setBackground(Color.GREEN);
            vacios ++;
            ocupados --;
            }
        }
    });

lo que hace mi codigo es que si se seleciona un boton el panel cambia de color a azul y si se des selecciona cambia a verde a su vez si se selecciona mueve los contadores y me muestra un mensaje indicandome que boton seleccione, si lo deselecciono vuelve a alterar los contadores como les digo funciona bien y hace lo que quiero ahora solo quiero optimizarlo para no repetirlo boton por boton

Gracias
« Última modificación: 27 de Junio 2018, 20:15 por Ogramar »

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re:Ayuda para hacer un array
« Respuesta #1 en: 17 de Mayo 2018, 00:27 »
No se donde tienes declarado el JButton rbtn1 o el JLabel lbl1, así que no tengo claro como está enfocado realmente el programa.

Pero bueno, da igual, hablemos del array.
La ventaja del array es poder agrupar muchos elementos en uno solo, de forma que puedes recorrerlos todos ellos de manera fácil usando un bucle.

Si quieres agrupar 105 botones, debes declarar un array como este.

Código: [Seleccionar]
JButton[] botones = new JButton[105];
Despues tienes que inicializar los 105 botones valiendote de un bucle for.
En ese mismo bucle, puedes establecerles un texto diferenciador usando el indice del bucle:
Código: [Seleccionar]
for (int i = 0; i < 105; i++) {
    botones[i] = new JButton("Boton_" + i);
}

Luego, para comprobar si alguno de esos botones está seleccionado de forma similar  a como tú lo estás haciendo, usamos otro bucle similar:
Código: [Seleccionar]
for (int i = 0; i < 105; i++) {
    if (botones[i].isSelected {
        //Cosas que hacer si este boton esta seleccionado
    }
    else {
        //Cosas que hacer si este boton NO esta seleccionado
    }
}

Ahora bien, por la parte de código que has puesto intuyo que tu botón no está solo, parece que forma parte de un JPanel y acompañado de al menos un JLabel.

Quizás entonces lo que necesites es un array de 105 JPanel, cada uno con su boton y su label o lo que sea...
Incluso tal vez lo ideal sería crear tu propia clase que herede de JPanel. En un archivo .java a parte, pero almacenado en el mismo package, se puede hacer algo así:

Código: [Seleccionar]
public class MiPanel extends JPannel {

    public JLabel etiqueta;
    public JButton boton;

    public MiPanel(String txtEtiqueta) {
        etiqueta = new JLabel(txtEtiqueta);
        boton = new JButton();
        add(etiqueta);
        add(boton);
    }
}

Esta clase crea un panel (con el layout por defecto, puedes cambiarlo por otro si quieres) con una etiqueta y un boton. Al crear un objeto a partir de esta clase, podemos pasarle a su constructor un texto para la etiqueta JLabel.
Nota:
Lo "correcto" sería que los atributos de la clase, el boton y la etiqueta, fuesen private y no public. Pero para este ejercicio y facilitar la tarea, se pueden poner como public.

Luego, igual que en el primer ejemplo, en el programa principal podemos declarar un array para albergar objetos de la clase que acabamos de crear.
Y con un bucle los instanciamos, pasandole un String para cada una de las 105 etiquetas

Código: [Seleccionar]
MiPanel[] misPaneles = new MiPanel[105];

for (int i = 0; i < 105; i++) {
    misPaneles[i] = new MiPanel("Lugar: " + i);
}

Luego, otro bucle para recorrer los 105 paneles de nuestra clase,a ver cual boton ha sido seleccionado.

Código: [Seleccionar]
for (int i = 0; i < 105; i++) {
    if (misPaneles[i].boton.isSelected()) {
        misPaneles[i].setBackgroundColor(Color.BLUE);
        String L1 = misPaneles[i].etiqueta.getText();
        lugar = L1;
        vacios --;
        ocupados ++;
        JOptionPane.showMessageDialog (null,"Selecciono el "+ L1 );
    }
    else {
        //codigo para cuando no esta seleccionado...
    }
}

No se si este código realmente funciona, o si bien se adaptaría a lo que realmente quieres conseguir.

Pero bueno, al menos creo que puede servirte para que veas como utilizar un array para ahorrar trabajo cuando tienes que trabajar con muchos elementos de un mismo tipo/clase.
« Última modificación: 17 de Mayo 2018, 00:31 por Kabuto »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

paloma8513

  • Sin experiencia
  • *
  • Mensajes: 2
  • cada dia aprendo mas
    • Ver Perfil
Re:Ayuda para hacer un array
« Respuesta #2 en: 17 de Mayo 2018, 19:07 »
Hola Gracias por tu respuesta Kabuto, ter comento lo que hice:

cree una nueva clase como me lo recomiendas con el codigo a continuacion agregando los import correspondientes que me marcaba netbeans.

Código: [Seleccionar]
package Ventanas;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class MiPanel extends JPanel {  //aqui corregi Jpannel por Jpanel

    public JLabel etiqueta;
    public JButton boton;

    public MiPanel(String txtEtiqueta) {
        etiqueta = new JLabel(txtEtiqueta);
        boton = new JButton();
        add(etiqueta);
        add(boton);
    }
}

Aqui no me marca ningun error y la clase se llama MiPanel.java.

Ahora en otro jframe nuevo llamado mis paneles he puesto el siguiente codigo agregando los imports que me indica netbeans y tampoco me marca errores.

Código: [Seleccionar]
package Ventanas;

import java.awt.Color;
import javax.swing.JOptionPane;


public class MisPaneles extends javax.swing.JFrame {
   
    public MisPaneles() {
        initComponents();
        }

 public static void main(String args[]) {   
    String lugar =("");
        int ocupados = 0;
        int vacios = 35;
        int lugares ;
       
        MiPanel[] misPaneles = new MiPanel[35];

            for (int i = 0; i < 35; i++) {
            misPaneles[i] = new MiPanel("Lugar: " + i);
        }
       
            for (int i = 0; i < 35; i++) {
            if (misPaneles[i].boton.isSelected()) {
                misPaneles[i].setBackground(Color.BLUE);
                String L1 = misPaneles[i].etiqueta.getText();
                lugar = L1;
                vacios --;
                ocupados ++;
                JOptionPane.showMessageDialog (null,"Selecciono el "+ L1 );
            }
            else {
                misPaneles[i].setBackground(Color.GREEN);
                vacios ++;
                ocupados --;
            }
}
        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new MisPaneles().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify                     
    // End of variables declaration                   
}

y desgraciadamente no hace nada, no me marca ningun error ejecuto el archivo y me muestra el jframe vacio.

Te comento, lo que yo hice para la tarea fue crear 35 botones uno por uno y si funciona, es mas ya entregue ese trabajo (no quiero que me hagan la tarea) solo me comentaron que hice mucho trabajo y que podia hacerlo mas rapido con el array,

aun no me queda claro como funciona el array pero seguire investigando

mi programa muestra una pantalla para selecionar un lugar de estacionamiento al principio muestra todos en verde ya que esta libres todos, conforme se van selecionando se ponen en azul y asi se quedan hasta que se deselecionan indicandonos que azul es ocupado (por eso los contadores) al selecionar un lugar me indica que lugar seleccione y ese dato lo envia a otra pantalla que gurda el valor, como te digo todo eso ya lo hice solo que boton por boton....

« Última modificación: 17 de Mayo 2018, 19:34 por paloma8513 »

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re:Ayuda para hacer un array
« Respuesta #3 en: 21 de Mayo 2018, 00:50 »
Hola.

A ver, para separar asuntos y no crear un mensaje demasiado grande, lo separaré en dos.

Primero:
Sobre los arrays. (también llamados vectores o arreglos).

Lo que hacen es agrupar un mismo tipo de dato, ya sean tipos primitivos como int, char, double... u objetos de clases complejas: String, Integer, JPanel, ...o cualquier clase creada por nosotros.

Al agruparse, todos los datos comparten el mismo nombre, que es el nombre que hayamos dado al array. Y cada dato está numerado con un indice, que empieza a partir de 0 (en algunos lenguajes empieza por el 1).

Si yo declaro un array de 10 enteros:
Código: [Seleccionar]
int[] arr = new int[10];Obtengo una estructura como esta:


Para referirme  a cada uno de estos elementos de forma individual, utilizo el nombre del array y entre corchetes la posicion que ocupa.
Ejemplo:
Código: [Seleccionar]
arr[0] = 34;
arr[4] = 27;

Supongamos que yo quiero sacar por pantalla los 10 valores del array.
Puedo hacer esto:
Código: [Seleccionar]
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
System.out.println(arr[3]);
System.out.println(arr[4]);
System.out.println(arr[5]);
System.out.println(arr[6]);
System.out.println(arr[7]);
System.out.println(arr[8]);
System.out.println(arr[9]);

Pero es mucho trabajo....Y eso que este array es pequeño, imagina que quiero sacar por pantalla un array de 100 elementos, o de 1000, o de 100000....
Menudo desproposito....

Por ello, lo normal es usar un bucle que vaya aumentando una variable int que usaremos como indice para recorrer las posiciones. Y para esto, el más cómodo es sin duda el bucle for:

Código: [Seleccionar]
for (int i = 0; i < 10; i++)
    System.out.println(arr[i]);
Esto haría lo mismo que el codigo anterior, solo que ahorrando trabajo.
Lo que hacemos es incrementar la variable i, para que vaya desde el 0 al 9 (por eso condicion del bucle es "mientras i < 10" ) y la usamos para recorrer cada elemento del array.

Pero, ¿qué ocurre si tenemos que escribir un código donde no sabemos cuanto mide el array que vamos a recorrer? Es muy habitual que tengamos que escribir un método capaz de operar con array de cualquier tamaño.
Para esto, podemos preguntarle directamente al array cuando mide consultando su propiedad .length

Código: [Seleccionar]
for (int i = 0; i < arr.length; i++)
    System.out.println(arr[i]);

Esto funcionará independientemente de si arr tiene una dimensión de 10, de 1000 o la que sea...
El bucle for sabe gracias a la propiedad .length cuánto mide el array y por lo tanto cuándo ha de detenerse.

Un error que debemos evitar es intentar acceder a posiciones del array que no existen ya que esto producirá una excepción y se detendrá el programa.

Siguiendo con el ejemplo de:
Código: [Seleccionar]
int[] arr = new int[10];
Son 10 elementos, numerados del 0 al 9.
Ergo, la posicion tope que puedo consultar es:
Código: [Seleccionar]
System.out.println(arr[9]);
Si hiciera:
Código: [Seleccionar]
System.out.println(arr[10]);
Tendríamos un error y el programa se terminaría de forma abrupta. A no ser que "capturemos" el error  y los gestionemos con las instrucciones try...catch... pero ese es otro tema.

Entonces, cuando te dijeron que podrías haberte ahorrado trabajo usando un array. Se referían a esto.
Si tu usaste 35 botones, seguramente tuviste que preguntar 35 veces, una para cada botón, si estaba seleccionado.
Agrupándolos en un array, solo hubieras tenido que preguntarlo una vez... poniendo la pregunta en un bucle for que recorriese las 35 posiciones del array que albergaba los botones.

Bueno, esto es en teoría...porque no es solo preguntar....
cada boton pertenece a un panel, cada boton tiene una etiqueta, cada panel ha de ver modificado su color, cada uno ha de lanzar un mensaje al ser seleccionado....

Si queremos automatizar todo esto para poder simplificarlo en una o pocas instrucciones dentro de un bucle, hay que aplicar lo mejor posible la filosofia POO (Programacion Orientada a Objetos) de modo que cada objeto/elemento del programa sea lo más autosuficiente posible y sepa comunicarse con el resto de elementos de forma eficiente.

Por eso propuse crear una clase propia para cada panel, para que cada panel se autogestione al ser pulsado su boton.
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re:Ayuda para hacer un array
« Respuesta #4 en: 21 de Mayo 2018, 00:51 »
Segundo:

El programa de Lugares.
Hablas de un programa donde hay 105 lugares disponibles, que tendrían dos estados posibles: "Libre" u "Ocupado".
Para pasar de un estado a otro nos servimos de un boton que posee cada uno de los 105 lugares y además contamos con unos contadores para tener en pantalla la cantidad de lugares libres y ocupados.

Eso he creído entender. Y más o menos, simplificandolo un poco, yo lo he representado así:



Para complicar el código lo menos posible, está todo escrito en un único archivo .java que contiente todos los métodos y subclases necesarias.

Ahora lo pongo completo, listo para ser copiado, compilado y ejecutado.
Pero luego vamos a ir comentándolo por partes:

Código: [Seleccionar]
package ocupados;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public final class LugaresOcupados {

private PanelLugares lugares = new PanelLugares();//Panel central con los botones para elegir Lugares
private PanelContador contador = new PanelContador();//Panel superior que informa de la cantidad de Lugares ocupados

public LugaresOcupados()
{
try {
SwingUtilities.invokeAndWait(new Runnable()
{
@Override
public void run()
{
JFrame ventana = new JFrame("Lugares Ocupados");
ventana.setLayout(new BorderLayout());
ventana.add(contador, BorderLayout.NORTH);//Colocamos el Panel del Contador en parte superior de la ventana
ventana.add(lugares, BorderLayout.CENTER);//Colocamos en Panel de Lugares en parte central de la ventana
ventana.pack();
ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ventana.setLocationRelativeTo(null);
ventana.setResizable(false);
ventana.setVisible(true);
}
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
}


public static void main(String[] args) {

new LugaresOcupados();
}

/**
* Esta clase crea un panel que representa un Lugar.
* Cuenta con un boton para marcar el lugar como "ocupado" o "libre"
*/
private final class Lugar extends JPanel{

private JButton boton;
private JLabel etiqueta;
private boolean libre = true;//Para saber si el Lugar esta libre o no
private int numLugar;

public Lugar(int nLugar)
{
numLugar = nLugar;
boton = new JButton("Libre");
boton.addActionListener(new PulsarBoton());
boton.setPreferredSize(new Dimension(85, 26));//Como el texto del boton cambiará, le damos un tamaño suficiente para que quepa
setBorder(BorderFactory.createLoweredBevelBorder());
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
etiqueta = new JLabel("Lugar #" + numLugar);
add(etiqueta);
add(boton);
setBackground(Color.GREEN);
}

/*
* Esta clase es para definir que ocurre cuando se pulsa el boton de un Lugar
*/
private class PulsarBoton implements ActionListener
{
@Override
public void actionPerformed(ActionEvent arg0) {
if (libre)
{
libre = false;
setBackground(Color.BLUE);
etiqueta.setForeground(Color.WHITE);//Cambiamos color texto etiqueta para que sea visible sobre el fondo azul
boton.setText("Ocupado");
}
else
{
libre = true;
setBackground(Color.GREEN);
etiqueta.setForeground(Color.BLACK);//Color texto etiqueta recupera color original
boton.setText("Libre");
}

contador.actualizarContador(lugares.calcularOcupados());//Actualizamos el contador de lugares ocupados

JOptionPane.showMessageDialog(null, "Se ha seleccionado el " + etiqueta.getText() +
"\nSu estado ahora es: " + boton.getText());
}
}
}

/**
* Esta clase es para definir el Panel central que albergará los 105 Lugares disponibles.
*/
private final class PanelLugares extends JPanel{

private Lugar[] lugares = new Lugar[105];//Array para agrupar los 105 objetos de la clase Lugar

public PanelLugares()
{
setLayout(new GridLayout(15, 7, 10, 10));//15 filas, 7 columnas = 105 celdas para colocar "Lugares"
//Los valores 10, 10 establece la separacion en pixeles entre los 105 paneles Lugar

//Creamos los 105 lugares y los vamos añadiendo al array y tambien al panel central
for (int i = 0; i < 105; i++)
{
lugares[i] = new Lugar(i);//Añadimos al array
add(lugares[i]);// Añadimos al Panel
}
}

/*
* Este metodo recorre todo el array preguntando a cada Lugar si esta libre o no.
* Si no lo está, es decir, que está ocupado, lo contará y luego devuelve el total de
* Lugares ocupados.
*/
public int calcularOcupados()
{
int ocupados = 0;
for (int i = 0; i < lugares.length; i++)
{
if (lugares[i].libre == false)
ocupados++;
}

return ocupados;
}

}

/**
* Esta clase crea el Panel superior donde estará el contador de lugares ocupados.
* Este contador se irá actualizando cada vez que se pulse un boton.
*/
private final class PanelContador extends JPanel{

private JLabel contadorLugares;

public PanelContador()
{
JLabel texto = new JLabel("Lugares ocupados: ");
texto.setFont(new Font("Tahoma", Font.PLAIN, 40));//Aumentamos tamaño del texto para mayor visibilidad
contadorLugares = new JLabel("0");
contadorLugares.setFont(new Font("Tahoma", Font.PLAIN, 40));
contadorLugares.setForeground(Color.RED);
add(texto);
add(contadorLugares);
}

/*
* Este metodo recibe el numero de lugares ocupados actualmente y
* con este valor actualiza la etiqueta que usamos como contador.
*/
public void actualizarContador(int valor)
{
contadorLugares.setText(String.valueOf(valor));
}

}
}

Esa ventana (JFrame) esta dividida en dos paneles (JPanel).
El panel superior es el "contador", que son tan solo dos etiquetas en la que una se irá actualizando cada vez que se pulse un boton indicando la cantidad de lugares ocupados.

El panel de abajo, ocupa practicamente toda la ventana y en realidad contiene 105 subpaneles, cada uno con su etiqueta y botón.

Cada uno de ellos es una clase llamada Lugar que hereda de JPanel.
Esta es la clase más importante del programa, ya que es donde ocurre toda "la acción" del programa.

Código: [Seleccionar]
private final class Lugar extends JPanel{

private JButton boton;
private JLabel etiqueta;
private boolean libre = true;//Para saber si el Lugar esta libre o no
private int numLugar;

public Lugar(int nLugar)
{
numLugar = nLugar;
boton = new JButton("Libre");
boton.addActionListener(new PulsarBoton());
boton.setPreferredSize(new Dimension(85, 26));//Como el texto del boton cambiará, le damos un tamaño suficiente para que quepa
setBorder(BorderFactory.createLoweredBevelBorder());
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
etiqueta = new JLabel("Lugar #" + numLugar);
add(etiqueta);
add(boton);
setBackground(Color.GREEN);
}

/*
* Esta clase es para definir que ocurre cuando se pulsa el boton de un Lugar
*/
private class PulsarBoton implements ActionListener
{
@Override
public void actionPerformed(ActionEvent arg0) {
if (libre == true)
{
libre = false;
setBackground(Color.BLUE);
etiqueta.setForeground(Color.WHITE);//Cambiamos color texto etiqueta para que sea visible sobre el fondo azul
boton.setText("Ocupado");
}
else
{
libre = true;
setBackground(Color.GREEN);
etiqueta.setForeground(Color.BLACK);//Color texto etiqueta recupera color original
boton.setText("Libre");
}

contador.actualizarContador(lugares.calcularOcupados());//Actualizamos el contador de lugares ocupados

JOptionPane.showMessageDialog(null, "Se ha seleccionado el " + etiqueta.getText() +
"\nSu estado ahora es: " + boton.getText());
}
}
}

Tiene 4 atributos:
Una etiqueta con el número del Lugar.
Un boton para realizar la accion de "Ocupar" o "Liberar"
Un boolean para que este panel pueda indicarnos si actualmente esta Libre o no.
Un int con su numero correspondiente, que puede ir del 0 al 104 (105 posiciones)

Su contructor recibirá el numero de Lugar que le corresponda y lo guardará en su atributo
numLugar
Despues inicializa el botón con el texto "Libre" ya que de inicio todos los Lugares estarán libres.
Le agrega un ActionListener, declarado un poco más abajo, que contiene el código que se ha de ejecutar cuando se pulse el boton.
Además le establece al boton un tamaño "Preferido". Esto es porque al ocupar un Lugar, cambiaremos el texto del boton de "Libre" a "Ocupado". El boton, al arrancar el programa, su panel adopta un tamaño adecuado para el texto "Libre", pero luego el boton no tendrá sitio en su panel para crecer y que quepa el texto "Ocupado".
Si previamente le establecemos un tamaño adecuado, reservará espacion para poder crecer cuando el texto cambie a "Ocupado"

Al panel le ponemos un Borde, esto no es importante, es puramente estético.

Luego le indicamos el Layout, es decir, como queremos que se repartan los objetos dentro del panel. EL layout que le estamos indicando es que los coloque en vertical, es decir, primero la etiqueta y debajo el boton.

Despues inicializamos la etiqueta, incluyendo en su texto el numero de posición que hemos recibido por el contructor de la clase.
Añadimos los dos elementos al panel y listo.

Luego escribimos el código del ActionListener.
En tu codigo usabas el metodo isSelected() para preguntar en cada acción, a todos los botones si estan seleccionados o no.

Yo no lo he hecho así, aquí directamente al pulsar un boton, le preguntamos a su panel si esta libre, valiéndonos del atributo booleano.
Si está "libre", es que ha de cambiar a "ocupado", por lo cuál cambiará su color, cambiará el texto del botón, hará que el contador (el contador pertenece a otra clase) se actualice y mostrará un mensaje en pantalla.
Si está "ocupado", cambiará a "libre", haciendo los cambios necesarios para ello.


Bien, la siguiente clase que encontramos es PanelLugares, que básicamente lo que hace es albergar en formar de cuadrícula, los 105 paneles correspondientes a la clase Lugar

Código: [Seleccionar]
private final class PanelLugares extends JPanel{

private Lugar[] lugares = new Lugar[105];//Array para agrupar los 105 objetos de la clase Lugar

public PanelLugares()
{
setLayout(new GridLayout(15, 7, 10, 10));//15 filas, 7 columnas = 105 celdas para colocar "Lugares"
//Los valores 10, 10 establece la separacion en pixeles entre los 105 paneles Lugar

//Creamos los 105 lugares y los vamos añadiendo al array y tambien al panel central
for (int i = 0; i < 105; i++)
{
lugares[i] = new Lugar(i);//Añadimos al array
add(lugares[i]);// Añadimos al Panel
}
}

/*
* Este metodo recorre todo el array preguntando a cada Lugar si esta libre o no.
* Si no lo está, es decir, que está ocupado, lo contará y luego devuelve el total de
* Lugares ocupados.
*/
public int calcularOcupados()
{
int ocupados = 0;
for (int i = 0; i < lugares.length; i++)
{
if (lugares[i].libre == false)
ocupados++;
}

return ocupados;
}

}

Aqui hace aparicion el array.
Es el único atributo de esta clase, un array de 105 elementos para los 105 paneles.
Lo útil de tenerlo en un array, como veremos luego, es que para actualizar el contador podemos recorrer el array y contar los paneles que indican que NO están libres (libre == false), es decir, que ESTAN OCUPADOS y una vez contados, actualizar el contador con este dato.
Esto podría haberse hecho sin usar una array, bastaría con incrementar o decrementar una variable int y habría sido más eficiente de hecho. Pero como es un ejercicio e interesa practicar con un array, pues aqui es donde mejor viene utilizarlo.

El constructor lo primero que hace es aplicar un Layout que divide el panel en 105 celdas, repartidas en 15 filas de 7 columnas. Con esta distribución conseguimos que todas las filas tengan el mismo numero de paneles.
Otra división valida sería 5 filas de 21 columnas, pero queda demasiado ancho y la ventana se saldría de los límites de la mayoría de pantallas de ordenador.
Este layout además establece una separacion de 10 pixeles, tanto en horizontal como en vertical, entre cada panel. Esto también es una decisión estética.

Despues, el constructor usa un bucle for para recorrer el array y crear un nuevo panel "Lugar", con su correspondiente numero de posición, y lo guarda en el array al mismo tiempo que lo añade a nuestro panel "PanelLugares".

Luego tenemos un método que como dije antes, mediante un bucle revisa que paneles "Lugar" están "ocupados, los cuenta y devuelve el valor.
Este valor lo recibirá el PanelContador, que es la clase que comentamos ahora:

Código: [Seleccionar]
private final class PanelContador extends JPanel{

private JLabel contadorLugares;

public PanelContador()
{
JLabel texto = new JLabel("Lugares ocupados: ");
texto.setFont(new Font("Tahoma", Font.PLAIN, 40));//Aumentamos tamaño del texto para mayor visibilidad
contadorLugares = new JLabel("0");
contadorLugares.setFont(new Font("Tahoma", Font.PLAIN, 40));
contadorLugares.setForeground(Color.RED);
add(texto);
add(contadorLugares);
}

/*
* Este metodo recibe el numero de lugares ocupados actualmente y
* con este valor actualiza la etiqueta que usamos como contador.
*/
public void actualizarContador(int valor)
{
contadorLugares.setText(String.valueOf(valor));
}

}

Consta de dos etiquetas, una con un texto que no cambia nunca. La otra es la que muestra el valor numérico de espacios ocupados e irá cambiando cada vez que se pulse un boton.
En el constructor he aumentado el tamaño de su fuente para que sea más visible.

Luego cuenta con un pequeño método que es el que se encarga de recibir el valor de lugares ocupados (del cual informa la clase PanelLugares) y modifica la etiqueta con el nuevo valor.



Estas tres clases que hemos comentado, son "clases anidadas" en la clase principal LugaresOcupados
Están anidadas, es decir, declaradas dentro de la clase principal y no por separado, para facilitar la comunicación entre ellas.
Lo elegante sería escribirlas por separado, pero entonces tendríamos ciertas dificultades que habría que complicar un poco el código para solventarlos y ahora no merece la pena.

La clase LugaresOcupados:
Código: [Seleccionar]
public final class LugaresOcupados {

private PanelLugares lugares = new PanelLugares();//Panel central con los botones para elegir Lugares
private PanelContador contador = new PanelContador();//Panel superior que informa de la cantidad de Lugares ocupados

public LugaresOcupados()
{
try {
SwingUtilities.invokeAndWait(new Runnable()
{
@Override
public void run()
{
JFrame ventana = new JFrame("Lugares Ocupados");
ventana.setLayout(new BorderLayout());
ventana.add(contador, BorderLayout.NORTH);//Colocamos el Panel del Contador en parte superior de la ventana
ventana.add(lugares, BorderLayout.CENTER);//Colocamos en Panel de Lugares en parte central de la ventana
ventana.pack();
ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ventana.setLocationRelativeTo(null);
ventana.setResizable(false);
ventana.setVisible(true);
}
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
}


public static void main(String[] args) {

new LugaresOcupados();
}

Es muy sencilla. Tiene dos atributos:
- un objeto de la clase PanelLugares (que a su vez contiene los 105 objetos de la clase Lugar)
- un objeto de la clase PanelContador

Su contructor crea la ventana (JFrame) principal y le da un Layout un tanto especial.
Este layout digamos que crea una zona central llamada CENTER rodeada de 4 zonas de menor tamaño en cada punto cardinal NORTH, SOUTH, EAST y WEST.
En este caso uso la zona NORTE para colocar el panelContador ya que necesita poco espacio.
La zona CENTRO que es la de mayor tamaño, colocamos el panel de Lugares.
EL resto de zonas (SUR, ESTE y OESTE) no van a contener nada, así que no aparecerán en la ventana.

Luego le decimos a la ventana que calcule el tamaño necesario para albergar todos los paneles:
Código: [Seleccionar]
ventana.pack();Le decimos que cierre el programa por completo cuando se pulse el boton X de la ventana:
Código: [Seleccionar]
ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);Le decimos que muestre la ventana centrada en la pantalla:
Código: [Seleccionar]
ventana.setLocationRelativeTo(null);Bloqueamos el tamaño de la ventana para que el usuario no lo modifique:
Código: [Seleccionar]
ventana.setResizable(false);Y hacemos la ventana visible:
Código: [Seleccionar]
ventana.setVisible(true);

Luego su metodo main() no hace nada especial, tan solo instanciar la clase principal para que la ventana y todo su contenido se ponga en marcha.

Lamento hacer posts taaaan laaarrgos. Hay casi más explicaciones que código, no te preocupes si te duermes antes de leerlo todo xD... leelo en varios intentos .

Tan solo decir que hay muchas formas de realizar un programa. Esta es mi solución, no tiene por qué ser la mejor. Solo espero que sea lo más entendible posible y te ayude en algo.

Lo importante aquí no es solo aprender a valerse de arrays cuando hay que operar con muchos elementos de un mismo tipo.
Si no también que hay que intentar aplicar la POO al máximo posible y conseguir que cada elemento sea autosuficiente.

En lugar de hacer un programa que al pulsar un boton, se pregunte al resto de los 104 botones si ha sido pulsado o no...
hay que conseguir que al pulsar un boton, este haga lo que tenga que hacer por su propia cuenta sin tener que consultarle al resto de botones.
« Última modificación: 21 de Mayo 2018, 01:14 por Kabuto »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

 

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".