views:

142

answers:

3

Please note I haven't tested this on a Windows-machine only on a Mac-machine. I'm not so sure whether this also occurs on a Windows-machine...

When I resize my Java-application the content is invisible. I already found a way to fix it after resizing it, but not while the user is resizing the window.

I'm not using Swing or something because it makes my binary so slow (in my opinion).

The structure is like this:

  • Frame My main-window
    • Container Content view of main-window
      • Container-based subviews that including the paint(Graphics g)-method

I've added all listeners to My main-window and now I'm able to redraw the Content-view after resizing the window.

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

I am beware of the fact using the paint(getGraphics())-method isn't a really good way to do this, but since the repaint()-method doesn't do anything at all, it's the only working possibility.

While resizing, all painted content becomes invisible. However, when I add a Button-instance to my Content-view and resize my Main-window, the button doesn't get invisible.

I am able to trace the 'live'-resize event:

public void componentMoved(ComponentEvent e) {
    System.out.println("Live-resize");
}
  1. When I start resizing this method is not being called.
  2. While resizing it generates "Live-resize" in my log every single pixel I resize the window.
  3. When I stop resizing this method is not being called, the componentResized-method does.

When I add my repaint-method (or the official repaint-method) to the 'live'-resize event like this, I still get the output, however, it's not repainting or something

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

Or

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

When I minimize my application to the dock and maximize the application again, the same thing happens, I guess that the same code is needed to fix this.

I'm not using Graphics2D or something, just Graphics.

Could you please explain me how I can repaint the views?

Thanks in advance, Tim

+2  A: 

I'm more familiar with Swing, but the article Painting in AWT and Swing distinguishes between system- and application-triggered painting. The example below shows how the system invokes paint() as the window is resized, while the application invokes repaint(), which calls update(), in response to a mouse event. The behavior is cross-platform.

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);
        }
    }
}
trashgod
+2  A: 

For reference, here is the same program using Swing. Because JPanel is double buffered, it doesn't flicker as the mouse is released after resizing.

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);
        }
    }
}
trashgod
A: 

Okay, I finally fixed it.

Instead of redrawing it every time in the paint(Graphics g)-method, you need to buffer the output and only redraw that image (I kinda hoped Java would be already doing that, just like 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);
}

Now, when you minimize the window and maximize it again, the paintings remain. Only, the window's flickering now for .1-second or so, but I don't really care about that.

Tim van Elsloo
Actually, `update()` already calls `paint()`; and `repaint()` works, as shown above. You don't need to buffer the output; it doesn't hurt to cache it using a `BufferedImage`, but avoid re-creating it repeatedly. You really should reconsider Swing, for example, this animation: https://sites.google.com/site/drjohnbmatthews/kineticmodel
trashgod