Autor Tema: Ayuda, pequeño problema eliminando JPanel en tiempo real  (Leído 268 veces)

Kabuto

  • Moderador Global
  • Avanzado
  • *******
  • Mensajes: 253
    • Ver Perfil
Hola a todos.
Por practicar y tal... estoy haciendo un programita en Java en el cual dentro de un JScrollPane, añado y elimino JPanels en tiempo real.
Añadir puedo añadir los que quiera, se van colocando uno debajo de otro.
Cada JPanel tiene un boton "Eliminar" para eliminar este Jpanel en cuestión.

Pues bien, por algún extraño motivo.... si hay más de 3 JPanels mostrándose , sí puedo ir eliminandolos...
Pero cuando ya solo hay dos, o bien solo hay uno...no se eliminan..
Bueno, en realidad, creo que si se eliminan, solo que parece que no se actualiza correctamente el JSCrollPane y siguen mostrándose en pantalla, aunque en realidad si han sido eliminados.

Y es extraño que esto solo falle cuando hay uno o dos paneles.
Como digo, si hay más paneles si se eliminan y se actualiza la pantalla correctamente.
Luego, en principio el código que uso es correcto, pero no entiendo porque falla solo en esa situacion.

El código que uso, tanto para añadir paneles como para eliminar, es en realidad muy sencillo, sin complicaciones.
- Hago un removeAll()
- Genero nuevos JPanel a partir de los datos contenidos en un ArrayList y los voy añadiendo al contenedor correspondiente.
- Por último hago un .revalidate()

Este es el método que se encarga de este proceso:
Código: [Seleccionar]
public void actualizarEncargos(ArrayList<Encargo> encargos) {
contenedor.removeAll();
System.out.println("Encargos.size() --> " + encargos.size()); //Info para debug
for (int i = 0; i < encargos.size(); i++)
{
PanelEncargo temp = new PanelEncargo(encargos.get(i));
temp.botonEliminar.addActionListener(new AccionEliminarPanel(i));
contenedor.add(Box.createRigidArea(new Dimension(0, 20)), -1);
contenedor.add(temp);
}
contenedor.revalidate();
}

Os paso un zip el código fuente completo, pero antes, sabiendo que es extremadamente complicado interpretar el código escrito por otra persona, me gustaría explicaros en que consiste mi programa, lo más resumidamente posible sin daros demasiado la paliza.

Intento hacer un programita muy simple para gestionar Encargos de productos que soliciten clientes.
En mi trabajo, a veces los clientes nos piden que traigamos cierto producto, o bien que les avisemos si por casualidad llega un determinado producto que se está retrasando.
Actualmente, estos encargos se anotan a mano en una agenda, pero muchas veces olvidamos repasar dicha agenda como es debido, o se pierde durante varios dias, o nadie se acuerda de quien tomó nota de un determindo encargo,..

En fin, un desastre.
Y se me ha ocurrido, con mis escasos conocimientos, intentar hacer un programita en Java para gestionar esto desde el ordenador, de forma mas visual.
La idea es que se guarden y muestren en pantalla los datos referentes a cada encargo que nos pidan.
Cada encargo está representado por un JPanel rectangular y se irán colocando uno debajo del otro. Además el color del JPanel varía según la fecha de antigüedad, mostrandose en rojo los encargos muy antiguos y que por lo tanto requieren algún tipo de accion inmediata.

Bueno en fín. Para ello, uso principalmente:
- una clase Encargo con los datos de los encargos que se pidan.
- una clase PanelEncargo, que hereda de JPanel y recibe un objeto Encargo para mostrar sus datos en pantalla.

Estoy siguiendo una estructura Modelo-Vista-Controlador:

Así que en la clase Modelo tengo un ArrayList para almacenar los Encargos que se vayan realizando.
Más adelante, pondré funcionalidad para guardar y recuperar este ArrayList serializandolo en un archivo.

La Vista, obviamente, se encarga de construir el JSCrollPane donde se van añadiendo y quitando los objetos PanelEncargo. Este JScrollPane se pasa luego a la clase principal, que es donde esta el JFrame que muestra lo que va haciendo la Vista.

Y el Controlador, pues nada, hace de nexo entre la Vista y el Modelo.

Hay alguna clase más, como un JDialog para crear Encargos, pero no es relevante ahora.

Bien, paso a explicar como se crean los PanelEncargo.
Lo que hago es que cojo del Modelo el ArrayList de Encargos.
Por cada Encargo, creo un PanelEncargo.
Cada PanelEncargo, muestra los datos del Encargo y tiene dos botones:
- uno para Modificar (que ahora mismo no funciona, no tiene ninguna implementacion todavia)
- otro para Eliminar.

Al boton Eliminar de cada PanelEncargo, le agrego este ActionListener

Código: [Seleccionar]
private class AccionEliminarPanel implements ActionListener {

int numeroPanel;

public AccionEliminarPanel(int nPanel) {
numeroPanel = nPanel;
}

@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Eliminando panel numero: " + numeroPanel); //Info para debug
controlador.eliminarEncargo(numeroPanel);
}
}

Ese atributo numeroPanel, lo uso para guardar el numero de indice que ocupa cada Encargo en el ArrayList.
Es decir, el Encargo en la posicion 0, su correspondiente PanelEncargo tiene un boton Eliminar "personalizado" que ya sabe que cuando se pulse, hay que decirle al Controlador que de orden al Modelo de eliminar el Encargo en la posicion 0.

Una vez eliminado, el Controlador le enviará a la Vista el ArrayList que acaba de cambiar.
Y la Vista eliminará TODOS los PanelEncargo presentes en pantalla, volverá a crear nuevos con los datos actuales del ArrayList de Encargos y "revalidará" el JScrollPane con los nuevos componentes actuales.

Bien, todo este proceso, no se si es eficiente, pero en principio es eficaz.
Y además es una forma fácil de conseguir que todos los PanelEncargo tengan los botones "Eliminar" actualizados. Porque cada vez que borro un Encargo, los indices del ArrayList varían, y por tanto los botones "Eliminar" se han de actualizar o de lo contrario podrían dar ordenes de eliminar Encargos que ya no existen o que ahora pertenece a otros PanelEncargo distintos.

Bueno, como digo, esto "funciona" bien cuando hay muchos PanelEncargo mostrándose en pantalla.
Pero, no se porque, cuando solo hay uno o dos, la Vista no se actualiza correctamente.
Los componentes son eliminados, es decir, el .removeAll() hace su cometido. Pero "visualmente" no se percibe y se quedan en pantalla unos PanelEncargo que en realidad ya no están.

El ArrayList de Encargos se actualiza correctamente, con unos System.out voy controlando como su tamaño aumenta o decrece en cada accion.
Y los botones "Eliminar" también se actualizan correctamente, pues también controlo cuando los pulso que indice van a dar orden de eliminar en el ArrayLsit, y siempre es correcto.

Así que el problema tiene que ser alguna pijada del Swing que yo desconozca, o yo que se...

Os adjunto un zip con el código fuente. No es necesario que os estudieis el código completo.
Quien pueda/quiera ayudarme que centre su neuronas en la clase Vista, en su método actualizarEncargos() que es quien añade/elimina los PanelEncargo.
Y es muy fácil reproducir el fallo. Basta generar tres o cuatro encargos usando la opción del menú superior.
Veréis que se van mostrando correctamente en pantalla.

Cuanto tengais tres o cuatro creados, empezad a eliminar.
Veréis que se van eliminando correctamente, hasta cuando quedan dos en pantalla.
Entonces fallará y no se eliminarán, bueno, más bien no se va a mostrar que SI han sido eliminados.

PD:
No me juzguéis por lo fea que es la interfaz  :-[
Está en fase alpha todavía jeje, cuando funcione la haré un poco más bonita.
Aunque no tengo mucho arte yo para esto, así que seguirá siendo fea, solo que entonces no tendré excusa.

Gracias a quien al menos me haya leído, y un saludo.

Kabuto

  • Moderador Global
  • Avanzado
  • *******
  • Mensajes: 253
    • Ver Perfil
Re:Ayuda, pequeño problema eliminando JPanel en tiempo real
« Respuesta #1 : 22 de Enero 2019, 11:52 »
Vale, problema solucionado gracias a alguien más sabio que yo.

Y la solución es tan simple, que me siento estúpido ja ja...

Basta con añadir un repaint() tras "revalidar" el contenedor de la Vista.
Tan simple como eso... y mira que le dí vueltas al asunto este y probé cosas raras.... pero en ningún momento se me ocurrió probar con algo tan evidenete como un repaint()  :o

Queda solucionado modificando así el método:
Código: [Seleccionar]
public void actualizarEncargos(ArrayList<Encargo> encargos) {
contenedor.removeAll();
System.out.println("Encargos.size() --> " + encargos.size()); //Info para debug
for (int i = 0; i < encargos.size(); i++)
{
PanelEncargo temp = new PanelEncargo(encargos.get(i));
temp.botonEliminar.addActionListener(new AccionEliminarPanel(i));
contenedor.add(Box.createRigidArea(new Dimension(0, 20)), -1);
contenedor.add(temp);
}
contenedor.revalidate();
contenedor.repaint();
}

Ogramar

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2488
    • Ver Perfil
Re:Ayuda, pequeño problema eliminando JPanel en tiempo real
« Respuesta #2 : 22 de Enero 2019, 22:06 »
Buenas, largos días se han perdido por problemas más insignificantes que ese... cosas de la programación  ???

 

Esto es un laboratorio de ideas...
Aprender a programar

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