我正在编写一个程序,绘制一列在屏幕上移动的火车。我将图形类与fillRect、drawOval和draw line方法一起使用。我在屏幕的右手边有一个启动火车的按钮。在从屏幕上消失后,它应该以随机的y位置重新出现并再次运行。这应该循环,直到单击停止按钮。问题是我使用thread.sleep()方法在程序更新列车位置之前暂停程序。由于某种原因,我无法在程序运行时单击任何按钮。关于如何让我的停止按钮工作,有什么想法吗?谢谢
这是我正在使用的代码。它还有JFrame表单在netbeans中的普通代码。
private void btnStartTrainActionPerformed(java.awt.event.ActionEvent evt) {
run = true;
while (run) {
Graphics g = jPanel1.getGraphics();
int x =0;
int y = (int)(Math.random() *500) + 20;
int smoke =1;
for( x = 900; x > -600; x--)
{
drawTrain(g, x, y, smoke);
try {
Thread.sleep(17);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
clearJFrame(g);
smoke++;
x = x-4;
}
if (x == -599)
{
x = 900;
y = (int)(Math.random() *500) + 20;
}
}
}
private void btnStopTrainActionPerformed(java.awt.event.ActionEvent evt) {
run = false;
}
public void drawTrain(Graphics g, int x, int y, int smoke)
{
// draw locomotive
g.setColor(Color.RED);
g.fillRect(x, y, 100, 30);
g.fillRect(x +100, y-30, 40, 60);
g.setColor(Color.BLACK);
g.fillRect(x +110, y-20, 20, 10);
g.drawLine(x +10, y, x, y-20);
g.drawLine(x +11, y, x, y-20);
g.drawLine(x, y-20, x +30, y-20);
g.drawLine(x +30, y-20, x +20, y);
g.drawLine(x +31, y-20, x +20, y);
g.drawLine(x, y+30, x-20, y+25);
g.drawLine(x-20, y+25, x-20, y+20);
g.drawLine(x-20, y+20, x, y+15);
g.drawOval(x +10, y+20, 25, 25); //draw wheels
g.drawOval(x +35, y+20, 25, 25);
g.drawOval(x +60, y+20, 25, 25);
g.drawOval(x +85, y+20, 25, 25);
g.drawOval(x +110, y+20, 25, 25);
if (smoke >20)
g.drawOval(x +8, y-33, 12, 12); // draw smoke
if (smoke >40)
g.drawOval(x +12, y-53, 12, 12);
if (smoke >60)
g.drawOval(x +18, y-73, 13, 13);
if (smoke >80)
g.drawOval(x +25, y-100, 14, 14);
if(smoke >100)
g.drawOval(x+31, y-120, 15, 15);
if (smoke > 120)
g.drawOval(x+37, y - 140, 16, 16);
if (smoke > 140)
g.drawOval(x+44, y-160, 17, 17);
g.setColor(Color.RED);
g.fillRect(x +160, y, 80, 30); // draw additional cars
g.fillRect(x +260, y, 80, 30);
g.fillRect(x +360, y, 80, 30);
g.setColor(Color.BLACK);
g.drawOval(x +160, y+20, 25, 25);
g.drawOval(x +215, y+20, 25, 25);
g.drawOval(x +260, y+20, 25, 25);
g.drawOval(x +315, y+20, 25, 25);
g.drawOval(x +360, y+20, 25, 25);
g.drawOval(x +415, y+20, 25, 25);
}
public void clearJFrame(Graphics g)
{
g.setColor(jPanel1.getBackground());
g.fillRect(0, 0, jPanel1.getWidth(), jPanel1.getHeight());
}
您正在事件调度线程上执行Thread.sleep()
,使GUI在该调用的整个持续时间内冻结。
延迟在GUI上执行操作的正确方法是使用Swing Timer对其进行调度。
当Swing程序需要执行长时间运行的任务时,您需要使用SwingWorker。事件调度线程上的阻塞将冻结您的GUI。
阅读oracle的这两个教程,你就会知道你应该做什么:
- http://docs.oracle.com/javase/tutorial/uiswing/concurrency/simple.html
- http://docs.oracle.com/javase/tutorial/uiswing/concurrency/interim.html
不幸的是,当您使用Swing(以及几乎所有的UI框架)时,您无法在UI线程(也称为Event Dispatch线程)中进行睡眠,因为实际上是这个线程管理整个UI。因此,通过睡眠,它在整个睡眠时间内变得没有反应是正常的。
您应该做的是从btnStartTrainActionPerformed
启动另一个线程,并在该线程中进行睡眠。
类似于:
private void btnStartTrainActionPerformed(java.awt.event.ActionEvent evt) {
Thread thread = new Thread() {
public void run()
{
run = true;
while (run)
{
Graphics g = jPanel1.getGraphics();
int x =0;
int y = (int)(Math.random() *500) + 20;
int smoke =1;
for( x = 900; x > -600; x--)
{
// Needed to make this change back on the UI Thread
SwingUtilities.invokeLater(new Runnable() {
public void run() {
drawTrain(g, x, y, smoke);
}
});
try
{
Thread.sleep(17);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
clearJFrame(g);
smoke++;
x = x-4;
}
if (x == -599)
{
x = 900;
y = (int)(Math.random() *500) + 20;
}
}
}
};
thread.start();
}