我这里有个问题。下面的程序创建一个动画(从一个点到另一个点的圆)。单击按钮时,动画应开始。
问题是当我单击按钮时,我看不到圆圈在滑动。一段时间后,它只是出现在其他地方。
对我来说(作为初学者)似乎很有趣,如果我不使用按钮,并在 go() 中调用 moveIt() 方法,我会得到一个正常的动画(我可以看到圆在滑动)。
你能给我一些关于这个问题的建议吗?
谢谢。
这是程序:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import java.awt.event.*;
final public class MiniMiniMusicPlayer1 implements ActionListener
{
JFrame frame;
DrawPanel drawPanel;
private int X = 7;
private int Y = 7;
public static void main(String... args)
{
new MiniMiniMusicPlayer1().go();
}
private void go()
{
frame = new JFrame("Player");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawPanel = new DrawPanel();
frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
JButton buttonStart = new JButton("Start animation");
frame.getContentPane().add(BorderLayout.SOUTH, buttonStart);
buttonStart.addActionListener(this);
frame.setResizable(false);
frame.setSize(300, 300);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent ev){
moveIt();
}
class DrawPanel extends JPanel
{
public void paintComponent(Graphics g)
{
g.setColor(Color.BLACK);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.RED);
g.fillOval(X, Y, 50, 50);
}
}
private void moveIt()
{
for (int i = 0; i < 100; ++i)
{
X++;
Y++;
try
{
Thread.sleep(10);
}
catch (Exception e)
{
e.printStackTrace();
}
frame.repaint();
}
}
}
Swing 和 AWT 使用事件调度线程工作。该线程负责处理所有事件(运行事件处理程序,例如按钮的actionPerformed
)和重绘请求。
当你从go
运行你的moveIt
时,它由主线程运行。它创建重绘请求,与主线程同时运行的事件调度线程调度这些请求。因此,您可以看到动画。
但是,当您从事件处理程序调用moveIt
时,它由事件调度线程本身运行。因此,将执行整个循环,并且所有重绘请求都排队,但线程很忙,并且在完成循环之前无法调度它们。
当它完成循环时,它会调度重绘(或者更确切地说,它只调度一个,不需要重绘 100 次)。重绘是在给定 X 和 Y 的最终状态的情况下完成的。
如果要查看动画,则应确保未在 EDT 中运行它们。例如,您可以为此使用 javax.swing.Timer
对象。
请记住,永远不要在事件处理程序中运行长时间的操作。它阻止了 EDT 并使您的 GUI 无响应。切勿在事件处理程序中使用Thread.sleep()
。如果您的长任务应该定期执行某些操作,请使用 Timer
。如果它应该执行一些大任务,例如从数据库加载,请使用 SwingWorker
.