En el desarrollo de interfaces gráficas con Java Swing, al modificar el estado de una ventana (como redimansionar, minimizar o maximizar), el sistema invoca automáticamente el método paint de cada componente. Esta llamada por defecto limpia el lienzo, provocando que cualquier dibujo personalizado desaparezca. Para evitar esta pérdida visual, es necesario implementar una lógica de redibujo que restaure los gráficos previos cada vez que el componente se repinta a sí mismo.
La solución se basa en la sobrescritura del método paint. Al hacerlo, debemos conservar el comportamiento original de pintado del componente utilizando super.paint(g), y añadir nuestras propias rutinas de dibujo. A continuación, se detalla este proceso utilizando un tablero de ajedrez y sus fichas como modelo.
Redibujo del Tablero
El tablero representa una estructura estática. Dado que su forma no varía, no requiere almacenar estado ni datos históricos; simplemente basta con volver a trazar las líneas dentro del método paint cada vez que se invoca.
import javax.swing.*;
import java.awt.*;
public class MarcoJuego extends JFrame {
public int margenX = 40, margenY = 60, celda = 50, lineas = 15;
@Override
public void paint(Graphics g) {
// Conserva la funcionalidad original de pintado del JFrame
super.paint(g);
// Trazado de la cuadrícula (elemento estático)
for (int i = 0; i < lineas; i++) {
int desplazamientoY = margenY + celda * i;
int desplazamientoX = margenX + celda * i;
int limiteX = margenX + celda * (lineas - 1);
int limiteY = margenY + celda * (lineas - 1);
g.drawLine(margenX, desplazamientoY, limiteX, desplazamientoY);
g.drawLine(desplazamientoX, margenY, desplazamientoX, limiteY);
}
}
}
Al sobrescribir paint, la llamada a super.paint(g) garantiza que la interfaz base se renderice correctamente antes de superponer nuestras líneas. El bucle se encarga de calcular los puntos de inicio y fin para dibujar tanto las líneas horizontales como las verticales de la cuadrícula.
Redibujo de las Fichas
A diferencia del tablero, las fichas son dinámicas. Si solo dibujáramos la ficha en pantalla, al repintarse la ventana desaparecería. Para que persistan, debemos guardar su información y utilizarla para reconstruirlas.
1. Modelado y Persistencia de Datos
Primero, creamos una clase encargada de almacenar las propiedades visuales de cada ficha y de encapsular su lógica de renderizado.
import java.awt.*;
public class Ficha {
private int coordenadaX, coordenadaY, dimension = 30;
private Color tono;
public Ficha(int coordenadaX, int coordenadaY, Color tono) {
this.coordenadaX = coordenadaX;
this.coordenadaY = coordenadaY;
this.tono = tono;
}
public void renderizar(Graphics g) {
g.setColor(tono);
g.fillOval(coordenadaX, coordenadaY, dimension, dimension);
}
}
Cuando el usuario coloca una ficha, instanciamos este objeto calculando sus coordenadas absolutas en píxeles a partir de la intersección de la cuadrícula y lo dibujamos pasándole el contexto Graphics.
Ficha nuevaPieza = new Ficha(posGridX * celda + margenX, posGridY * celda + margenY, colorActual);
nuevaPieza.renderizar(graphicsContext);
Sin embargo, una variable simple solo guarda la última referencia. Para conservar múltiples fichas, implementamos un arreglo con un índice de control:
public Ficha[] historialFichas = new Ficha[lineas * lineas];
public int contador = 0;
// Al agregar una ficha:
historialFichas[contador] = nuevaPieza;
contador++;
El arreglo debe ser lo suficientemente amplio para albergar todas las jugadas posibles (en este caso, el producto de las dmiensiones del tablero), y el contador avanza secuencialmente para evitar sobrescribir posiciones anteriores.
2. Recuperación y Redibujo
El arreglo de fichas debe ser accesible desde el marco principal para que el método paint pueda leerlo. Al invocarse el repintado, iteramos sobre el arreglo, verificamos la existencia de datos y ordenamos a cada objeto que se dibuje a sí mismo.
// Dentro de la clase MarcoJuego
public Ficha[] historialFichas; // Recibido desde el controlador de eventos
@Override
public void paint(Graphics g) {
super.paint(g);
// ... (código de dibujo del tablero) ...
// Redibujo dinámico de las fichas
if (historialFichas != null) {
for (Ficha pieza : historialFichas) {
if (pieza != null) {
pieza.renderizar(g);
}
}
}
}
La validación pieza != null es crucial, ya que el arreglo contendrá espacios vacíos antes de que el juego alcance su capacidad máxima. De esta forma, solo se invoca renderizar sobre las fichas efectivamente colocadas, completando el ciclo de persistencia gráfica.