您的代码违反了几个Swing规则,包括:
-
不要在组件上使用getGraphics来获取Graphics对象。该对象将是短暂的,并且可能在某个时刻为null。
-
不要从后台线程或任何其他非Swing事件调度线程中进行Swing调用。
相反
-
使用Swing Timer来驱动动画,
-
在paintComponent方法中进行绘制。
-
一定要打电话给
super.paintComponent(g)
方法覆盖组件,以便可以进行内务绘制
-
请注意,应该覆盖JPanel(或从JComponent扩展的其他对象)的paintComponent方法,而不是覆盖绘制方法,因为默认情况下,paintComponent会为您提供双重缓冲,使动画更平滑。
例如
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.*;
public class SwingGui01 extends JPanel {
private JComboBox<String> comboBox = new JComboBox<>(new String[]{"One", "Two", "Three", "Four", "Five"});
private AnimationPanel animationPanel = new AnimationPanel();
public SwingGui01() {
setLayout(new BorderLayout());
add(comboBox, BorderLayout.PAGE_START);
add(animationPanel);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Swing GUI 01");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SwingGui01());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
class AnimationPanel extends JPanel {
private static final int DELTA_X = 5;
private static final int DELTA_Y = DELTA_X;
private static final int PREF_W = 400;
private static final int PREF_H = 300;
private static final int ANIMATION_DELAY = 20;
private static final Color BACKGROUND = Color.MAGENTA;
private int x = 0;
private int y = 0;
private int deltaX = DELTA_X;
private int deltaY = DELTA_Y;
public AnimationPanel() {
setBackground(BACKGROUND);
Timer timer = new Timer(ANIMATION_DELAY, e -> {
if (y > getHeight() - 50 ) {
deltaY = -DELTA_Y;
} else if (y < 0) {
deltaY = DELTA_Y;
}
if (x > getWidth() - 50) {
deltaX = -DELTA_X;
} else if (x < 0) {
deltaX = DELTA_X;
}
x += deltaX;
y += deltaY;
repaint();
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
@Override
protected void paintComponent(java.awt.Graphics g) {
super.paintComponent(g);
g.fillOval(x, y, 50, 50);
}
}