Reputation: 1
I'm writing a program that draws a train that moves across the screen. I'm using the graphics class with the fillRect, drawOval, and draw lines methods. I have a button that starts the train on the right hand side of the screen. After disappearing off screen, it should reappear with random y location and run again. This should loop until the stop button is clicked. The problem is I'm using the thread.sleep() method to pause the program before it updates the train's position. For some reason, I can't click any buttons while the program is running. Any ideas on how to make my stop button work? Thanks.
Here's the code I am using. It also has the normal code that a JFrame form has in 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());
}
Upvotes: 0
Views: 807
Reputation: 4779
Unfortunately, when you work with Swing (and almost every UI framework) you cannot put a sleep like you do right in the UI thread (also called the Event Dispatch Thread), because, its really this thread that manages the whole UI. So, by sleeping it, its normal that it becomes unresponsive for the whole sleeping duration.
What you should do is to start another thread from btnStartTrainActionPerformed
and make the sleep in this thread instead.
Something like :
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();
}
Upvotes: 0
Reputation: 6521
When a Swing program needs to execute a long-running task, you need to use SwingWorker. Blocking on the Event Dispatch Thread will freeze your GUI.
Read these two tutorial from oracle, and you'll know what you should do:
Upvotes: 2
Reputation: 200206
You are executing Thread.sleep()
on the Event Dispatch Thread, making the GUI freeze for the entire duration of that call.
The proper way to delay an action to be taken on the GUI is by scheduling it using the Swing Timer.
Upvotes: 3