I've made leaps and bounds in skill and progress since joining this community. You all are a huge help. I'm having trouble with giving a timer that I've implemented certain parameters for when it starts and stops.
I either get errors saying "the local variable timer may not have been initialized" or I get no errors, but nothing happens. Maybe I have the timer in the wrong place?
If I put timer.start(); in the constructor too everything works fine, but then the timer has to start when the program is initialized. I would really like to have the timer not start until a certain parameter is met. Say, for instance, until the int p1Laps=1; but if I place timer.start(); into an if-statement in the constructor (i.e. if(p1Laps>=1) { timer.start(); } the timer doesn't ever start.
I've tried placing timer.start(); in various places and have either gotten no response or generated an error about the lack of local variable timer.
A second, somewhat related problem I have is the inability to put any parameters in place to call on timer.stop(); without getting the aforementioned "local variable timer may not have been initialized" error. I've left timer.stop(); where I think it needs to be in the code, but it receives that error.
So in short, I want to be able to tell the timer to start when a parameter is met, namely when a player has completed a lap. And I want to be able to tell the timer to stop when it reaches a value.
Thanks in advance for the great advice I'm sure I'll receive. Note: this is not the whole code, just relevant information.
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
public class RacerDoom extends JFrame {
int counter = 0;
int p1Laps = 0;
public RacerDoom() {
//create JFrame
super("Racer Doom Squared");
setSize(WIDTH,HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
//set up Timer
final Timer timer=new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(counter>=10) {
timer.stop(); //error here reads "local variable timer may
//not have been initialized"
}
else{
counter++;
}
System.out.println(counter);
}
});
//inner class threads
Move1 m1 = new Move1();
m1.start();
//start timer
if(p1Laps>=1) {
timer.start(); //error here is that timer will not start when
//p1Laps>=1
}
}
private class Move1 extends Thread implements KeyListener {
public void run() {
addKeyListener(this);
while(true) {
try {
repaint();
//collisions
if(p1.intersects(finishtop)&&p1Direction==UP&&p1cross!=true){
p1cross=true;
p1Laps++;
p1Boost++;
counter=0;
System.out.println(p1Laps);
}
if(p1.intersects(finishtop)==false) {
p1cross=false;
}
public static void main (String [] args) {
new RacerDoom();
}
}
As you want to start and stop the timer at different places in the code you should make it member variable. This will fix the problem where you are trying to stop the timer inside the action listener.
The variable p1Laps will not change in the constructor (after you have initialized it to 0) so you need to start the timer where you change the value of plLaps. I am not sure if it is safe to call timer.start() from another thread (Move1). So it may be safer to start timer with SwingUtilities.invokeLater().
Quick fix:
Rather than
timer.stop();
Do
((Timer)e.getSource()).stop();
The ActionEvent's getSource method will return a reference to the object that calls the actioPerformed method (the Timer), so this should work.
There may be other issues with your code including your background thread without a Thread.sleep(...), your use of KeyListeners rather than Key Binding, your adding a KeyListener in a background thread,...
Related
So i want to print out a word every second for 10 seconds, but nothing is working
Here's my code:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class Main{
public static void main (String[] args){
class TimerListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
System.out.println("helo");
}
}
ActionListener dummy = new TimerListener();
Timer power_up_time = new Timer(10000,dummy);
power_up_time.addActionListener(dummy);
power_up_time.start();
}
}
EDIT: so i added the start function and it still doesnt work
I believe that you need to start a Timer in order to make it work.
Something like this:
Timer timer = new Timer(500, new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
timer.start();
In newer versions of Java (from the last ten years or so) I would suggest using a ScehduledExecutorService
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ses.scheduleAtFixedRate(() -> System.out.println("hello"), 0, 1, TimeUnit.SECONDS);
TimeUnit.SECONDS.sleep(10);
ses.shutdown();
If the code you posted is complete you are starting the timer right before the application (i.e. the main thread) terminates. Thus the scheduler won't run long enough to execute the timer.
Try sleeping or running in a loop with some exit condition (that's probably what you'll want to do anyways).
You do not initialize and start the Swing toolkit, hence your application immediately terminates.
If you really want to use the Swing Timer, you need to show at least some window or dialog, so that the Swing event thread is running, e.g. by adding the following to the end of your main() method:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JFrame("Frame title").setVisible(true);
}
});
See the other answers for alternatives outside of Swing.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class TimeController {
public static void main(String arg[]){
TimeController m = new TimeController();
System.out.println("starting");
m.start();
}
Timer timer = new Timer (1000, new ActionListener(){
public void actionPerformed(ActionEvent e) {
System.out.println("Running");
}
});
public void start(){
timer.start();
}
}
I think there is no fault at all.
The Timer starts its task in the background
Your application terminates before the first execution of the Timers method takes place.
For testing you could add
try {
Thread.sleep(5000);
} catch(Exception e){
// Add exception handling
}
right after `m.start();
For some reason the Timer needs to fire at least once to prevent the program from termination. After it fires once, it does hold the program running, even after the main method terminates.
Probably the bug got unnoticed as this is a rather unusual work flow. Delay the termination of the main thread as proposed by #StefanFreitag.
i'm using a label for a little sprite for some testing that i'm doing, but i want to move the sprite 10 pixels per keypress. Now, i can do that, but now i'm trying to make it move the 10 pixels smoothly, so i tried the next code:
for(int i = 0; i < 100; i++){
x++;
container.setLocation(x, y);
System.out.println(x);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Now the problem is that, the sprite only moves when the for cycle ends, but the console shows the X value changing for each iteration. Any thoughts/help?
Thanks!
I suggest you to take a look at how to animate a JComponent using Swing Timer class, instead of for loop. You can find various tutorials about how to use Swing Timer. Here, to briefly explain, you are blocking EDT(Event Dispatch Thread) which operates the graphical side of the Java. Whenever you want to make a constant and smooth flow in your animations, make sure that you never block the EDT.
EDIT: Here is the demonstration of the usage of Swing Timer Class:
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
public class AnimationTrial extends JFrame {
private final int DELAY = 10;
private Timer timer;
private int x, y;
private JLabel label;
public static void main(String[] args) {
EventQueue.invokeLater( new Runnable () {
#Override
public void run() {
new AnimationTrial();
}
});
}
public AnimationTrial()
{
setSize(500, 500);
x = 50;
y = 50;
label = new JLabel("They see me movin' they hatin'!");
timer = new Timer( DELAY, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent arg0) {
x++;
label.setLocation(x, y);
}
});
timer.start();
getContentPane().add(label);
pack();
setVisible (true);
}
}
If you dont create new Thread, the user interface runs on the same thread as its method.
Therefore your for-cycle is fired after some action and thread cant do anything else until it ends.
Solution : Create your own class, pass the JLabel or the whole form as parameter in constructor, implement threading and run it as new thread.
I'd suggest you give a look to the Timing Framework, if you want to do something close to an animation in Swing. It could help you, depending on your general need.
If you want other sprites to move in sync with your sprite you can create a TimerTask and use scheduleAtFixedRate(). Your TimerTask would then be responsible for moving all sprites and redrawing everything that was part of the moving like the JPanel in the background and the sprites.
To make your code snippet work you would have to add redrawing of the Background and the sprite after setting the location but I would advise against that approach as it can easily lead to badly designed code where you create one God Class that does everything.
The TimerTask approach should also be more precise if the calculations need a bit time as it tries to have the same time between 2 calls where the approach with the sleeping thread can easily lead to different delays if the calculations are finished earlier or later.
I need to make a GUI where a worker enters a station (a spot on the panel) and stays there for a set amount of seconds, shown in a countdown about the workers head (so, once the workers moves to the spot, the station's label shows 3s -> 2s -> 1s and then the worker leaves, and the label reverts back to "OPEN"). I'm having trouble with making this happen, as I'm not too good with the Timer(s?) that Java has. I tried with something like this:
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e)
{
//change label text/color, decrement countdown
panel.repaint();
Thread.sleep(1000);
}
});
But I can't reach the number of seconds to count down from from inside the timer, and I'm not sure how to pass that value to the timer. If someone can help me out, I'd really appreciate it.
Get rid of the Thread.sleep(). That's what the 1000 in Timer(1000, new ActionListener() does. It sets an interval for each timer event. Every time a timer event is fired, the actionPerformed is called. So you need to determine what needs to happen every "tick", and put that code in the actionPerformed. Maybe something like
Timer timer = new Timer(1000, new ActionListener() {
private int count = 5;
#Override
public void actionPerformed(ActionEvent e) {
if (count <= 0) {
label.setText("OPEN");
((Timer)e.getSource()).stop();
count = 5;
} else {
label.setText(Integer.toString(count);
count--;
}
}
});
You need to decide when to call timer.start().
For general information, see How to Use Swing Timers
Problem #1: You are calling Thread.sleep() from within the Swing GUI thread. That causes the thread to stop taking input and freeze. Delete that line. It does you no good! While you are at it, delete the repaint call as well.
Now that that's said and done, instead of creating an anonymous instance of ActionListener, you can create an actual class that implements ActionListener and provides a constructor. That constructor can have as an argument the number of seconds you want to start counting down. You can declare that class inside the method you are using, or you can declare it inside the class.
Here's a skeletal example:
public class OuterClass {
JLabel secondsLabel = ...;
Timer myTimer;
private void setupTimer(int numSecondsToCountDown) {
secondsLabel.setText(Integer.toString(numSecondsToCountDown));
myTimer = new Timer(1000, new CountdownListener(numSecondsToCountDown));
myTimer.start();
}
// ...
class CountdownListener implements ActionListener {
private int secondsCount;
public CountdownListener(int startingSeconds) { secondsCount = startingSeconds; }
public void actionPerformed(ActionEvent evt) {
secondsLabel.setText(Integer.toString(secondsCount);
secondsCount--;
if (secondsCount <= 0) { // stop the countdown
myTimer.stop();
}
}
}
}
I made a blackjack game, and I want the AI player to pause between taking cards. I tried simply using Thread.sleep(x), but that makes it freeze until the AI player is done taking all of his cards. I know that Swing is not thread safe, so I looked at Timers, but I could not understand how I could use one for this. Here is my current code:
while (JB.total < 21) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println("Oh noes!");
}
switch (getJBTable(JB.total, JB.aces > 0)) {
case 0:
JB.hit();
break;
case 1:
break done;
case 2:
JB.hit();
JB.bet *= 2;
break done;
}
}
BTW, the hit(); method updates the GUI.
so I looked at Timers, but I could not understand how I could use one for this
The Timer is the solution, since as you say you are updating the GUI which should be done on the EDT.
I'm not sure what your concern is. You deal a card and start the Timer. When the Timer fires you decide to take another card or hold. When you hold your stop the Timer.
Well, the following code shows a JFrame with a JTextArea and a JButton. When the buttons is clicked, the Timer send the event repeatedly (with a second delay between them) to the actionListener related to the button which appends a line with the current time.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.Timer;
public class TimerTest extends JFrame implements ActionListener{
private static final long serialVersionUID = 7416567620110237028L;
JTextArea area;
Timer timer;
int count; // Counts the number of sendings done by the timer
boolean running; // Indicates if the timer is started (true) or stopped (false)
public TimerTest() {
super("Test");
setBounds(30,30,500,500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(null);
area = new JTextArea();
area.setBounds(0, 0, 500, 400);
add(area);
JButton button = new JButton("Click Me!");
button.addActionListener(this);
button.setBounds(200, 400, 100, 40);
add(button);
// Initialization of the timer. 1 second delay and this class as ActionListener
timer = new Timer(1000, this);
timer.setRepeats(true); // Send events until someone stops it
count = 0; // in the beginning, 0 events sended by timer
running = false;
System.out.println(timer.isRepeats());
setVisible(true); // Shows the frame
}
public void actionPerformed(ActionEvent e) {
if (! running) {
timer.start();
running = true;
}
// Writing the current time and increasing the cont times
area.append(Calendar.getInstance().getTime().toString()+"\n");
count++;
if (count == 10) {
timer.stop();
count = 0;
running = false;
}
}
public static void main(String[] args) {
// Executing the frame with its Timer
new TimerTest();
}
}
Well, this code is a sample of how to use javax.swig.Timer objects. In relation with the particular case of the question. The if statement to stop the timer must change, and, obviously, the actions of the actionPerformed. The following fragment is a skeleton of the solution actionPerformed:
public void actionPerformed(ActionEvent e) {
if (e.getComponent() == myDealerComponent()) {
// I do this if statement because the actionPerformed can treat more components
if (! running) {
timer.start();
runnig = true;
}
// Hit a card if it must be hitted
switch (getJBTable(JB.total, JB.aces > 0)) {
case 0:
JB.hit();
break;
case 1:
break done;
case 2:
JB.hit();
JB.bet *= 2;
break done;
}
if (JB.total >= 21) { // In this case we don't need count the number of times, only check the JB.total 21 reached
timer.stop()
running = false;
}
}
}
IMHO this resolves the problem, now #user920769 must think where put the actionListener and the starting/stopping conditions...
#kleopatra: Thanks for show me the existence of this timer class, I don't know nothing about it and it's amazing, make possible a lot of tasked things into a swing application :)
Well, a quick explanation about Timers.
First of all, you need a java.util.Timer variable in your class and another class in your project which extends from java.util.TimerTask (let's call it Tasker).
The initialization of the Timer variable is so easy:
Timer timer = new Timer();
Now the Tasker class:
public class Tasker extends TimerTask {
#Override
public void run() {
actionToDo(); // For example take cards
}
// More functions if they are needed
}
Finally, the installation of the timer with its related Tasker:
long delay = 0L;
long period = pauseTime;
timer.schedule(new Tasker(),delay,period);
The schedule function indicates the following:
Fisrt param: Action to do each period milliseconds (Executes the run function of a TimerTask class or its extension)
Second param: When the timer must start. In this case, it starts when the schedule function is called. The following example indicates a starting 1 second after call the schedule function: timer.schedule(new Tasker(),1000,period);
Third param: milliseconds between one call of Tasker.run() function and the following call.
I hope you understand this microtutorial :). If you have any problem, ask for more detailed information!
Kind regards!
I think that in this tutorial is clear how to use Timers in order to achieve what you want, without having to deal with Threads.