(V1) I have a countdown object that deals with displaying a countdown on the JFrame by using a timer. Once the countdown goes to 0, I want the timer to stop and the game to start. However, I realized that even when my countdown isn't finished, my startGame() method is being run, and I cannot find a solution to make it so that the startGame() method only runs after the timer is stopped. So, my question is: is there anyway to make sure the startGame() only runs AFTER the countdown hits zero?
(V2) I tried using countdown.getTimer.isRunning()in the init() method to check whether or not the timer is running (if not then call startGame()) but that didn't seem to work. I'm guessing this is because at the time the if block is called, the timer is still running, so that's why startGame() isn't called... Is this why?
A little explanation of the code: the startCountdown() method tries to display the next image while hiding the last, so I have the catch for the first case where it tries to hide a non-existant image at an index that is out of bounds. Each time the timer ticks, I decrement sec by 1 until it is 0, and then the timer stops.
V1
public void init() {
countdown.startCountdown();
countdown.getTimer().start();
startGame();
}
public void startCountdown() {
timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
if (sec == 0) {
countdownIcons.get(0).setVisible(false);
timer.stop();
}
countdownIcons.get(sec - 1).setVisible(true);
countdownIcons.get(sec).setVisible(false);
} catch (IndexOutOfBoundsException exception) {
if (sec == 0) {
timer.stop();
}
}
sec--;
System.out.println(sec);
}
});
}
V2
public void init() {
countdown.startCountdown();
countdown.getTimer().start();
if (!countdown.getTimer().isRunning()) {
startGame();
}
}
The problem is that the Timer method runs on a separate thread, different from your main thread.
The way I see it there are two possible solutions:
call your startGame() method inside startCountdown(), not inside init();
the second solution would be to pause your main thread and wait for startCountdown() to finish, something like this should work:
public void init() {
countdown.startCountdown();
countdown.getTimer().start();
// pause main thread until timer is notified
synchronized(timer){
timer.wait()
startGame();
}
}
public void startCountdown() {
timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
if (sec == 0) {
countdownIcons.get(0).setVisible(false);
timer.stop();
// notify your current thread that it can resume execution
synchronized(timer){
timer.notify();
}
}
countdownIcons.get(sec - 1).setVisible(true);
countdownIcons.get(sec).setVisible(false);
// try not to catch this runtime exception and fix what causes IndexOutOfBoundsException
} catch (IndexOutOfBoundsException exception) {
if (sec == 0) {
timer.stop();
}
}
sec--;
System.out.println(sec);
}
});
}
Related
I am having an issue with a piece of my code in Java, it seems to be creating an endless loop.
public void progress(){
x = 3;
timer = new Timer(800, new ActionListener() {
public void actionPerformed(ActionEvent evt){
System.out.println(x);
x--;
if(x < 1){
UI();
timer.stop();
}
}
});
timer.start();
}
The method UI asks for input via SavitchIn, and it doesn't seem to run the line. I print before I ask for input in the UI method, and the print works just fine. When I remove this timer from my code, and keep the UI method the same, it works fine. Prints and then takes input. I've added a timer.stop() in UI method as well, and I am positive the timer is stopped, however after running the program I am forced to Reset the Virtual Machine the next time around otherwise it wont run. Any help is appreciated!
Your UI() method likely should be called on a background thread as it is likely tying up the Swing event thread (this we have to guess since you don't show it). So create a SwingWorker or a background thread and do this call in there. For more on this, please read Concurrency in Swing.
e.g.,
public void progress() {
x = 3;
timer = new Timer(800, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
System.out.println(x);
x--;
if (x < 1) {
new Thread(new Runnable() {
public void run() {
UI();
}
}).start();
timer.stop();
}
}
});
timer.start();
}
I am trying to create a circuit timer using the countdown timer. When the thread is sleeping I want the text to display "Change!" and this to display for 5 seconds before the countdown timer starts again. I am unsure how to get this working. I know the thread is sleeping and so wont display the "Change!" until after it has woke up again after the 5 seconds. But I cannot understand how to get it working the way I wish it to. Can anyone help me solve this issue?
public void onFinish()
{
// Text to be displayed when thread is sleeping
time.setText("Change!");
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
if (numberOfCircuits != 15)
{
start();
numberOfCircuits++;
}
else
{
countDownTimer.cancel();
}
}
Instead of making the main thread sleep(you are likely to get an ANR dialog), you can use a Timer which can notify you of your 5sec lapse and you can schedule your CountDownTimer again.
public void onFinish()
{
// Text to be displayed when thread is sleeping
time.setText("Change!");
new Timer("Sleeper").schedule(new TimerTask() {
#Override
public void run() {
if (numberOfCircuits != 15)
{
start();
numberOfCircuits++;
}
else
{
countDownTimer.cancel();
}
}
}, 5000); // 5 sec delay
}
I have 6 objects in the class GUI which are moving through the code:
Anim anim = new Anim();
Timer timer = new Timer();
timer.scheduleAtFixedRate(anim, 30, 30);
When an object comes to a point I want to stop it. In class Anim I'm doing:
public class Anim extends TimerTask {
#Override
public void run() {
if (t1.x == 300 && t1.y == 300) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
It stops application, and I want have stayed at a concrete object. How to do it?
EDIT:
Ok, now it works well, does not interfere with other objects. But the object is moving on and after 1 second back to the starting position. I wish the whole time he was in the same position when a sleep.
if (Main.auto1.x == 700 && Main.auto1.y == 350) {
timer = new javax.swing.Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
Main.auto1.x = 700;
Main.auto1.y = 350;
}
});
timer.setRepeats(false);
timer.start();
Use Swing Timer instead of Thread.sleep() and Java Timer in a Swing application that sometime hangs the Swing applicaion.
Read more How to Use Swing Timers
Sample code:
private Timer timer;
...
timer = new javax.swing.Timer(3000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
//do what ever you want to do
// call timer.stop() when the condition is matched
}
});
timer.setRepeats(true);
timer.start();
EDIT
Please have a look at my another post How to fix animation lags in Java?
How exactly do i call the .interrupt() method? When I have Thread.sleep(1000), when and where do I call the .interrupt() method? is it after? What I want to do is stop Thread.sleep(1000) midway.
EDIT::
i'm having trouble stopping a thread in the middle. This is part of my code, in the StoplightThread class I have problems on the first if statement. What it is supposed to do is wait at least 10 secs then allow the user to press the button so they can change the light, if the button is pressed it should stop the running thread in this case Thread.sleep(40000). What happens is when I press the button it changes the light but does not stop the thread. If I press the button while there is still 20secs left it will add 20secs to the 10secs for the yellow light, making it yellow for 30 secs.
Edit: if you are wondering, stoplightCanvas.x == 3 is green, stoplightCanvas.x == 2 is yellow, and stoplightCanvas.x == 1 is red.
class StoplightCanvas extends Canvas implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == cross) {
isPressed = true;
if (x == 3 && canCross)
x = 2;
}
repaint();
}
}
class StoplightThread extends Thread
{
StoplightCanvas stoplightCanvas;
StoplightThread(StoplightCanvas stoplightCanvas) {
this.stoplightCanvas = stoplightCanvas;
}
public void run()
{
if (stoplightCanvas.x == 3){
Thread.sleep(10000);
stoplightCanvas.canCross = true;
Thread.sleep(40000);
if(stoplightCanvas.isPressed)
StoplightThread.interrupt();
} else if (stoplightCanvas.x == 2) {
Thread.sleep(10000);
} else if (stoplightCanvas.x == 1) {
Thread.sleep(60000);
}
} catch (InterruptedException e){}
stoplightCanvas.toggleColor();
stoplightCanvas.repaint();
}
}
}
If you were going to call interrupt() at all, you'd call it from a different thread than the sleep().
If you want to interrupt the sleep() midway from the same thread, you can do this:
Thread.sleep( 500 );
...
Thread.sleep( 500 );
All that said, sleep() can be a code smell.
EDIT (after OP edit):
Call interrupt() on the StoplightThread from the GUI thread in your actionPerformed() method.
try this example
public class Test1 {
public static void main(String[] args) throws Exception {
Thread t = new Thread() {
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.start();
Thread.sleep(1000);
t.interrupt();
}
}
it prints
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at test.Test1$1.run(Test1.java:9)
You need a reference to the thread you want to interrupt, so that you can call interrupt() on it from a different thread.
I am making a simple target shooting game.I have a countdownTimer inside the label and an object that blinks in a random position inside the panel. Every time I click on the object,. the object's timer stops which makes that object stop too, but the countdown timer doesn't and that is my problem. I want the countdown timer should stop also.
Could someone help me about this matter?
Here's the code :
private void starting()
{
new Timer(TIMER_PERIOD, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
if (count++ < MAX_COUNT)
{
String text = "Time remaining: (" + (MAX_COUNT - count) + ") seconds left";
setCountDownLabelText(text);
Date date = new Date();
setCountDownPanelText(date);
}
else
{
((Timer) e.getSource()).stop();
randomTimer.stop();
JOptionPane.showMessageDialog(null, "Game Over");
System.exit(0);
}
}
}).start();
}
It strikes me that you don't understand the code at all, that you are unaware of the anonymous class created that is extending Timer, which (if you'd seen the documentation) has a function stop() which does what you ask.
You need to store a reference to the Timer.
private javax.swing.Timer timer;
private void starting() {
timer = new Timer(TIMER_PERIOD, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
// do stuff
// stop the timer
timer.stop();
// do other stuff
}
}
}