Swing 是一个单线程环境。也就是说,所有更新和交互都在单个线程中执行。Swing 也不是线程安全的。这意味着对 UI 的所有更新都必须在该线程(事件调度线程或 ETD)的上下文中执行。
任何阻止 EDT 的代码都会阻止它(除其他外)重新绘制 UI 并响应用户的输入。
您的绘制代码将永远不会更新屏幕,实际上它会使您的应用程序看起来“挂起”,因为该paint
方法不允许完成并且阻塞了 ETD。
paint
方法被调用后会快速返回,并且可能会快速连续重复调用,这是一个例外。
一般来说,aThread
可能有点过头了,javax.swing.Timer
在这种情况下,像 a 这样的东西会更合适。
public class AnimatedBoat {
public static void main(String[] args) {
new AnimatedBoat();
}
public AnimatedBoat() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new AnimationPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class AnimationPane extends JPanel {
private BufferedImage boat;
private int xPos = 0;
private int direction = 1;
public AnimationPane() {
try {
boat = ImageIO.read(new File("boat.png"));
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
xPos += direction;
if (xPos + boat.getWidth() > getWidth()) {
xPos = getWidth() - boat.getWidth();
direction *= -1;
} else if (xPos < 0) {
xPos = 0;
direction *= -1;
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public Dimension getPreferredSize() {
return boat == null ? super.getPreferredSize() : new Dimension(boat.getWidth() * 4, boat.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int y = getHeight() - boat.getHeight();
g.drawImage(boat, xPos, y, this);
}
}
}
作为旁注。您应该很少需要覆盖像orpaint
这样的顶级容器的方法,虽然这样做有很多充分的理由,但您最感兴趣的一个事实是它们不是双缓冲的,这意味着当屏幕更新时,您可能会看到闪烁。JApplet
JFrame
最好使用类似的东西JPanel
并覆盖它的paintComponent
方法。
看一眼
了解更多信息
nb 虽然我在JFrame
示例中使用了 a ,但将动画面板放入 a 将是一件简单的事情JApplet
,这是您不需要/不想从顶级容器扩展的另一个原因;)