我有两个几乎相同的类:AnimationFrame1和AnimationFrame2。这两个类都显示一个蓝色球在500 x 500窗口中水平来回移动。除了runAnimation()和createAndShowGUI()方法外,这两个类是相同的。在其runAnimation()方法中,AnimationFrame1使用while循环和sleep方法来创建动画循环,而AnimationFrame2使用Swing Timer。在它的createAndShowGUI()方法中,AnimationFrame1创建一个新线程并在其上调用runAnimation()方法,而AnimationFrame2只是简单地调用没有新线程的runAnimation()方法。为什么Java swing定时器比睡眠导致动画不稳定?
在编译这两个类之后,我发现使用Swing Timer的AnimationFrame2会显示更平滑的动画,与AnimationFrame1(使用while循环和sleep方法)中显示的动画不一样多。我的问题是:为什么AnimationFrame1的动画显示比AnimationFrame2更多?我为此寻找了一个理由,但迄今为止一无所获。另外,我显然是一个Java新手,所以请让我知道,如果你看到我的代码有任何问题,或者如果你知道我可以改进它的任何方式。
这里是AnimationFrame1:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
class AnimationFrame1 extends JPanel {
int ovalX;
int prevX;
Timer timer;
boolean moveRight;
BufferedImage img;
public AnimationFrame1() {
setPreferredSize(new Dimension(500, 500));
}
public void runAnimation() {
moveRight = true;
img = null;
ovalX = 0;
prevX = 0;
while(true) {
if (moveRight == true) {
prevX = ovalX;
ovalX = ovalX + 4;
}
else {
prevX = ovalX - 4;
ovalX = ovalX - 4;
}
repaint();
if (ovalX > 430) {
moveRight = false;
}
if (ovalX == 0) {
moveRight = true;
}
try {
Thread.sleep(25);
}
catch(Exception e) {
}
}
}
public void paintComponent(Graphics g) {
if (img == null) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = getGraphicsConfiguration();
img = gc.createCompatibleImage(78, 70);
Graphics gImg = img.getGraphics();
gImg.setColor(getBackground());
gImg.fillRect(0, 0, getWidth(), getHeight());
gImg.setColor(Color.BLUE);
gImg.fillOval(4, 0, 70, 70);
gImg.dispose();
}
g.drawImage(img, ovalX, 250, null);
}
public static void createAndShowGUI() {
JFrame mainFrame = new JFrame();
final AnimationFrame1 animFrame = new AnimationFrame1();
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.add(animFrame);
mainFrame.pack();
mainFrame.createBufferStrategy(2);
mainFrame.setVisible(true);
new Thread(new Runnable() {
public void run() {
animFrame.runAnimation();
}
}).start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
这里是AnimationFrame2:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
class AnimationFrame2 extends JPanel {
int ovalX;
int prevX;
Timer timer;
boolean moveRight;
BufferedImage img;
public AnimationFrame2() {
setPreferredSize(new Dimension(500, 500));
}
public void runAnimation() {
moveRight = true;
img = null;
ovalX = 0;
prevX = 0;
timer = new Timer(25, new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (moveRight == true) {
prevX = ovalX;
ovalX = ovalX + 4;
}
else {
prevX = ovalX - 4;
ovalX = ovalX - 4;
}
repaint();
if (ovalX > 430) {
moveRight = false;
}
if (ovalX == 0) {
moveRight = true;
}
}
});
timer.start();
}
public void paintComponent(Graphics g) {
if (img == null) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = getGraphicsConfiguration();
img = gc.createCompatibleImage(78, 70);
Graphics gImg = img.getGraphics();
gImg.setColor(getBackground());
gImg.fillRect(0, 0, getWidth(), getHeight());
gImg.setColor(Color.BLUE);
gImg.fillOval(4, 0, 70, 70);
gImg.dispose();
}
g.drawImage(img, ovalX, 250, null);
}
public static void createAndShowGUI() {
JFrame mainFrame = new JFrame();
final AnimationFrame2 animFrame = new AnimationFrame2();
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.add(animFrame);
mainFrame.pack();
mainFrame.createBufferStrategy(2);
mainFrame.setVisible(true);
animFrame.runAnimation();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
他如何睡在UI线程? 'Thread.sleep()'方法是从'runAnimation()'方法调用的,该方法在一个'Runnable'内被调用,传递给一个新的'Thread'。 – BenCole
@BenCole谢谢指出 - 我已经修改。 – assylias
@assylias感谢您的帮助,但使用volatile时没有任何变化。当你使用动画时,你会获得更流畅的动画吗? – CogStudent