After scratching around I found that it's best to implement a custom image component by extending a JLabel. So far that has worked great as I can add multiple "images" (jlabels without the layout breaking. I just have a question that I hope someone can answer for me.
- I noticed that in order to animate JLabels across the screen I need to
setlayout(null);
andsetbounds
of the component and then to animate eventuallysetlocation(x,y);
. Is this a best practice or a terrible way to animate a component? I plan on eventually making an animation class but I don't want to do so and end up having to chuck it.
I have included relevant code for a quick review check.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class GraphicsPanel extends JPanel {
private Timer timer;
private long startTime = 0;
private int numFrames = 0;
private float fps = 0.0f;
private int x = 0;
GraphicsPanel() {
final Entity ent1 = new Entity();
ent1.setBounds(x, 0, ent1.getWidth(), ent1.getHeight());
add(ent1);
//ESSENTIAL
setLayout(null);
//GAMELOOP
timer = new Timer(30, new ActionListener() {
public void actionPerformed(ActionEvent e) {
getFPS();
incX();
ent1.setLocation(x, 0);
repaint();
}
});
timer.start();
}
public void incX() { x++; }
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setClip(0, 0, getWidth(), getHeight());
g2.setColor(Color.BLACK);
g2.drawString("FPS: " + fps, 1, 15);
}
public void getFPS()
{
++numFrames;
if (startTime == 0) {
startTime = System.currentTimeMillis();
} else {
long currentTime = System.currentTimeMillis();
long delta = (currentTime - startTime);
if (delta > 1000) {
fps = (numFrames * 1000) / delta;
numFrames = 0;
startTime = currentTime;
}
}
}
}
Thank you!
Well, this is not entirely true. You can just play with the location and the label will move around the screen. However, if you ever resize the frame or anything then the layout manager will be invoked and the label will be repositioned and the location defined by the layout manager which in the case of a FlowLayout will be the top/left of the panel. Animation will then continue from that location. So in reality, yes, this is exactly what you need to do.
I find it the easiest way to do animation since Swing will automatically repaint the "last" location of the component (to restore the background) as well as paint the new location of the component. This is all achieved by a single setLocation() method.
Some people like to do custom painting by drawing the image directly on the panel, but then you are responsible for clearing the old location of the image so the background is redrawn and then draw the image in the new location. I find this too much work.