Reputation: 48
I am trying to render a complicated set of objects, and instead of trying to render each object individually, I thought it would be faster to render them as a BufferedImage. The only way I could figure out how to do that was to turn the BufferedImage into an ImageIcon, and set that to a JLabel, and add the JLabel to the JFrame. To update the image, I remove the JLabel, set it with the new BufferedImage, and re-add it to the JFrame. This makes the screen flash rapidly as you can see an empty frame in between each rendering. If I don't remove the label, the program runs extremely slowly. How do I fix this? Should I even be using JLabels or is there a better way?
public static void createWindow() {
frame = new JFrame("PlanetSim");
frame.setPreferredSize(new Dimension(WINDOW_X, WINDOW_Y));
frame.setMaximumSize(new Dimension(WINDOW_X, WINDOW_Y));
frame.setMinimumSize(new Dimension(WINDOW_X, WINDOW_Y));
foregroundLabel = new JLabel(new ImageIcon(foreground));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(foregroundLabel);
frame.pack();
frame.setVisible(true);
}
public static void setForeground() {
frame.getContentPane().remove(foregroundLabel);
foregroundLabel = new JLabel(new ImageIcon(foreground));
frame.getContentPane().add(foregroundLabel);
frame.pack();
}
I doubt the problem has to do with the loop itself, but I'm including it anyway just in case.
public void run() {
long lastTime = System.nanoTime(), now; //keeps track of time on computer in nanoseconds
double amountOfTicks = 60.0; //number of ticks per rendering
double delta = 0; //time step
long timer = System.currentTimeMillis(); //timer to display FPS every 1000 ms
int frames = 0;
while (running) {
now = System.nanoTime();
delta += (now - lastTime) * amountOfTicks / 1000000000;
lastTime = now;
while(delta >= 1) {
tick();
delta--;
}
if (running)
render();
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println("FPS: " + frames);
frames = 0;
}
}
}
public void render() {
populateWindow();
Window.setForeground();
}
Upvotes: 0
Views: 560
Reputation: 324197
frame.getContentPane().remove(foregroundLabel);
foregroundLabel = new JLabel(new ImageIcon(foreground));
frame.getContentPane().add(foregroundLabel);
frame.pack();
I would suggest there is no need to remove/add the label or pack the frame since I would assume the Icon will be the same size every time.
All you need to do is replace the Icon of the label.
//frame.getContentPane().remove(foregroundLabel);
foregroundLabel.setIcon( new ImageIcon(foreground) );
//frame.getContentPane().add(foregroundLabel);
//frame.pack();
I am trying to render a complicated set of objects, and instead of trying to render each object individually, I thought it would be faster to render them as a BufferedImage
Otherwise just do the rendering in your paintComponent()
method. Swing is double buffered by default so it essentially removes the need to create the BufferedImage.
See: get width and height of JPanel outside of the class for an example of custom painting. Just update the ball count from 5 to 100 to make it more complex.
Upvotes: 1