I'm trying to make a simple GUI program without using JComponents. Currently, I have a BufferedImage that I draw to off screen so that it doesn't flicker (or so I thought).
I made a new program here to replicate the issue:
package Main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class Main {
private final static JFrame frame = new JFrame();
private final static Panel panel = new Panel();
public static void main(String[] args) {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setPreferredSize(new Dimension(1000, 750));
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
while (true) {
panel.setBackgroundColour(Color.WHITE);
panel.setBackgroundColour(Color.BLACK);
panel.repaint();
}
}
private static class Panel extends JPanel {
private final BufferedImage offScreen = new BufferedImage(1000, 750, BufferedImage.TYPE_INT_ARGB);
private final Graphics graphics = offScreen.getGraphics();
@Override
protected void paintComponent(Graphics graphics) {
graphics.drawImage(offScreen, 0, 0, null);
}
public void setBackgroundColour(Color colour) {
graphics.setColor(colour);
graphics.fillRect(0, 0, 1000, 750);
}
}
}
In the example above, I made the screen turn black, and then white (offscreen). What I'd expect is that paintComponent() only displays the white screen. Instead, a black screen is showed as well, but everything is flickered.
Am I just using Graphics2D incorrectly, or should I just use BufferStrategy to incorporate my double buffering needs?
My best guess is you have a race condition, where your
while-loop
is trying to update theBufferedImage
, but Swing is also trying to paint it, meaning they are getting dirty updates between them. Also, you might be thrashing the Event Dispatching Thread, which could have it's own, long term issues.After some playing around, I was able to get something like this to work...
All it does is injects a small delay (25fps) between the updates, allowing Swing time to render the result.
You have to remember at two things with Swing,
repaint
doesn't happen immediately and may not happen at all, depending on what theRepaintManager
decides to do. Second, you don't control the painting process.Swing uses a passive rendering algorithm, meaning that painting will occur when it's needed, many times without your knowledge or intervention. The best you can do is make suggestions to the framework when you want something updated
See Painting in AWT and Swing and Performing Custom Painting for more details.