Contenido pintado invisible al redimensionar en Java

Tenga en cuenta que no he probado esto en una máquina Windows solo en una máquina Mac. No estoy seguro de si esto también ocurre en una máquina con Windows …

Cuando cambio el tamaño de mi aplicación Java, el contenido es invisible. Ya encontré la forma de arreglarlo después de cambiar el tamaño, pero no mientras el usuario cambia el tamaño de la ventana.

No estoy usando Swing o algo así porque hace que mi binario sea tan lento (en mi opinión).

La estructura es así:

  • Frame Mi ventana principal
    • Contenido Vista de contenido de main-window
      • Subvistas basadas en contenedores que incluyen el método de paint(Graphics g)

He agregado todos los oyentes a My main-window y ahora puedo volver a dibujar la Vista de contenido después de cambiar el tamaño de la ventana.

 public void componentResized(ComponentEvent e) { this.contentView.paint(this.contentView.getGraphics()); } 

Tengo cuidado con el hecho de usar la paint(getGraphics()) -method no es una buena manera de hacer esto, pero como el método repaint() no hace nada, es la única posibilidad de trabajo.

Al redimensionar, todo el contenido pintado se vuelve invisible. Sin embargo, cuando agrego un Button -instance a mi Content-view y cambio el tamaño de mi Main-window , el botón no se vuelve invisible.

Puedo rastrear el evento de cambio de tamaño ‘en vivo’:

 public void componentMoved(ComponentEvent e) { System.out.println("Live-resize"); } 
  1. Cuando empiezo a cambiar el tamaño de este método no se está llamando.
  2. Mientras que el cambio de tamaño genera “Live-resize” en mi registro cada píxel, cambio el tamaño de la ventana.
  3. Cuando dejo de cambiar el tamaño de este método no se está llamando, el método componentResized lo hace.

Cuando agrego mi método de repintado (o el método de repintado oficial) al evento de cambio de tamaño “en vivo” como este, sigo obteniendo el resultado, sin embargo, no está repintando o algo así

 public void componentMoved(ComponentEvent e) { System.out.println("Live-resize"); this.contentView.paint(this.contentView.getGraphics()); } 

O

 public void componentMoved(ComponentEvent e) { System.out.println("Live-resize"); this.contentView.repaint(); } 

Cuando minimizo mi aplicación al dock y vuelvo a maximizar la aplicación, sucede lo mismo, supongo que se necesita el mismo código para solucionarlo.

No estoy usando Graphics2D o algo así, solo Graphics .

¿Podría explicarme cómo puedo volver a pintar las vistas?

Gracias de antemano, Tim

    Como referencia, aquí está el mismo progtwig que usa Swing. Debido a que JPanel tiene doble buffer, no parpadea ya que el mouse se libera después del cambio de tamaño.

     import java.awt.*; import java.awt.event.*; import java.util.Random; import javax.swing.*; public class SwingPaint { public static void main(String[] args) { JFrame frame = new JFrame(); frame.add(new CirclePanel()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); } private static class CirclePanel extends JPanel { private static final Random r = new Random(); public CirclePanel() { this.setPreferredSize(new Dimension(320, 240)); this.setForeground(new Color(r.nextInt())); this.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { CirclePanel.this.update(); } }); } public void update() { this.setForeground(new Color(r.nextInt())); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); Dimension size = this.getSize(); int d = Math.min(size.width, size.height) - 10; int x = (size.width - d) / 2; int y = (size.height - d) / 2; g.fillOval(x, y, d, d); g.setColor(Color.blue); g.drawOval(x, y, d, d); } } } 

    Estoy más familiarizado con Swing, pero el artículo Painting in AWT and Swing distingue entre pintura activada por sistema y aplicación. El siguiente ejemplo muestra cómo el sistema invoca a paint() medida que la ventana cambia de tamaño, mientras que la aplicación invoca a repaint() , que llama a update() , en respuesta a un evento de mouse. El comportamiento es multiplataforma.

     import java.awt.*; import java.awt.event.*; import java.util.Random; public class AWTPaint { public static void main(String[] args) { Frame frame = new Frame(); frame.add(new CirclePanel()); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.pack(); frame.setVisible(true); } private static class CirclePanel extends Panel { private static final Random r = new Random(); public CirclePanel() { this.setPreferredSize(new Dimension(320, 240)); this.setForeground(new Color(r.nextInt())); this.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { CirclePanel.this.repaint(); } }); } @Override public void update(Graphics g) { this.setForeground(new Color(r.nextInt())); } @Override public void paint(Graphics g) { Dimension size = this.getSize(); int d = Math.min(size.width, size.height) - 10; int x = (size.width - d) / 2; int y = (size.height - d) / 2; g.fillOval(x, y, d, d); g.setColor(Color.blue); g.drawOval(x, y, d, d); } } } 

    De acuerdo, finalmente lo solucioné.

    En lugar de volver a dibujarlo cada vez en el método paint(Graphics g) , necesita almacenar el resultado y solo volver a dibujar esa imagen (esperaba que Java ya lo hiciera, al igual que Obj-C).

     public BufferedImage buffer; public void redraw() { buffer = new BufferedImage( 200, // height 300, // width BufferedImage.TYPE_4BYTE_ABGR); // ABGR = RGBA, 4-byte (r, g, b, a) per pixel Graphics g = buffer.getGraphics(); // do your drawing here if (this.getGraphics()) { // 'this' is already shown, so it needs a redraw this.paint(this.getGraphics()); // little hack } } public void update(Graphics g) { this.paint(g); } public void paint(Graphics g) { g.drawImage(buffer, 0, 0, this); } 

    Ahora, cuando minimizas la ventana y la vuelves a maximizar, las pinturas permanecen. Solo que la ventana parpadea ahora por un segundo o más, pero realmente no me importa eso.