Java Update JLabel in a loop - java

Sorry for posting yet another thread about Java swing and loops. I have read through others and none of the solutions have really been appropriate for me. Okay so now onto the problem. I have a class extending JFrame in which I have a Timer running a stopwatch as below:
class StopWatch extends TimerTask{
public void run() {
time.setText(String.format("%02d:%02d", minutes_elapsed,seconds_elapsed));
seconds_elapsed++;
if(seconds_elapsed == 60){
seconds_elapsed = 0;
minutes_elapsed++;
}
}
}
Now the only way my Label "time" updates is when I call time.update(time.getGraphics()) but this paints over the previous time. Any ideas what I should do? I have also tried repaint,validate,and paint. Paint does the same thing for me that update does...Any Ideas?
P.S I don't know if it matters or not but I create the Timer in a public void start_timer() function which is like below:
public void start_timer(int minutes, int seconds){
if(timer == null)
timer = new Timer();
timer.scheduleAtFixedRate(new StopWatch(),0,1000);
}

I suspect you're using a java.util.Timer instead of a javax.swing.Timer. The latter will make sure that the timer runs on the UI thread, which I suspect is the problem.
See "How to use Swing Timers" for a tutorial on them. You'll want to convert your TimerTask into an ActionListener`, and then use
timer.setDelay(1000);
timer.setRepeats(true);
timer.start();

You can do this
public void run()
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
// do stuff
}
}
));
}
but you really should be using the javax.swing.Timer though. Remember that Swing is single-threaded and as such, its components must be modified in its thread (i.e. Event Dispatch Thread).

Related

Java timer wont run

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.

Wait a few seconds in Swing

I need to wait a few seconds between invoking two different methods in a program with Swing interface. Those methods are not related to the GUI.
firstMethod();
//The interface is changed by other methods
...
//I want to Wait five seconds
secondMethod();
I have tried using a Swing Timer but it does not work. Apparently, the Timer starts but is a non-blocking action, so secondMethod() is executed immediately. I can use sleep(), but that freezes the GUI for those five seconds, so the interface is not updated until after that, which I would prefer to avoid.
I have found here some recommendations to use Future<V> and I have read the Javadoc but I have never used ExecutorService before and I am afraid I may write a too complex piece of code for something that simple.
Any idea on how to do it?
Sounds like your code is something like:
firstMethod();
startTimer();
secondMethod();
I have tried using a Timer but it does not work
You can't just start a Timer and do nothing. When the timer fires you need to invoke the secondMethod(...) in the actionPerformed of the Timer.
Use Swing Timer instead of Java Timer and Thread.sleep.
Please have a look at How to Use Swing Timers
Timer timer = new Timer(5000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
secondMethod();
}
});
timer.setRepeats(false);
timer.start()
A timer won't just stop code execution like sleep does.
You have to assign an ActionListener to it which will be notified when the time is up.
It goes something like this:
firstMethod();
Timer t = new Timer(5000);
t.setRepeats(false);
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
secondMethod();
}
})
t.start();

How to destroy a thread?

I'm making simple game, here is the code:
public class Game extends Canvas implements Runnable {
public void start() {
t = new Thread(this);
t.start();
}
#Override
public void run() {
setVisible(true); // visibility of the thread turn on
while (!t.isInterrupted()) {
if(condition for end the game) {
t.interrupt(); //here i need to destroy the thread
setVisible(false); //visibility to off
}
update();
render();
try {
Thread.sleep(20);
} catch(InterruptedException e) {}
}
}
}
I have another class which extends JFrame and this class is introducing main menu, if my "condition for end the game" is true, the thread dissapears and the menu is visible again, its good, but if i want to start new game again, the behavior of the thread is strange- its seems like the Thread.sleep() method changed from 20 to 10 because all its going faster, probably i need to kill the thread, but i dont know how, thanks
Simple, break the loop:
if(condition for end the game) {
t.interrupt(); //here i need to destroy the thread
setVisible(false); //visibility to off
break;
}
You end the loop and the thread will end.
The easiest way to terminate a Thread is to exit the run function. There is no special handling required, a simple return does the trick.
For you game you might want to consider using a ScheduledExecutorService, which allows you to schedule a Runnable to run at a fixed rate:
executor.scheduleAtFixedRate(gameLoop, 0, 1000/TARGET_FPS, TimeUnit.MILLISECONDS);
Keep in mind that you then need to take out the actual looping of your gameLoop, because that is done by the fixed-rate calling, which will reduce it to:
public void run() {
if (pause == false) {
update();
render();
}
}
Where pause is a boolean should you for some reason want to put the rendering on pause for a while.
With this setup you can terminate the game simply by calling executor.shutdown() which will then suppress any further calls to the runnable.
Not really on-topic, but I'm making a game too, and for pacing I'm using Timer (from swingx):
public class MainGameLoop implements ActionListener{
Timer timer;
public static void main(...){
timer = new Timer(10, this);
timer.start();
}
public void actionPerformed(ActionEvent e) {
...
}
}
Working well to me.

Java: setText() and threads

I am a beginner in java and unfortunately I was stuck on this problem. In code:
NewJFrame.java :
public class NewJFrame extends JFrame {
public void showText() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
jLabel1.setText("in show()"); //it does not work
System.out.println("in show()"); //it works
}
});
}
public NewJFrame() {
initComponents();
jLabel1.setText("start"); //it works
}
public static void main(String args[]) {
Timer timer = new Timer();
timer.schedule(new NewClass(), 1000, 2000);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
}
private javax.swing.JLabel jLabel1;
}
NewClass.java :
package newpackage;
import java.util.TimerTask;
class NewClass extends TimerTask {
public void run() {
System.out.println("in NewClass.run()"); //it works
new NewJFrame().showText();
}
}
I have a problem with the fact that the setText does not set jLabel1 when is called from timer thread. I tried to solve the problem using invokeLater(), but still does not work.
Thanks for your help.
The JLabel is never added to any container. Why would it appear?
As general advice, don't extend frame, simply keep a reference and as mentioned by #Reimeus, use a Swing Timer.
You are creating a new instance of NewJFrame in NewClass which never gets displayed:
new NewJFrame().showText();
You would need to pass the visible instance to NewClass for it to be updated.
However, better to use javax.swing.Timer rather than java.util.Timer to interact with Swing components. From How to Use Swing Timers:
In general, we recommend using Swing timers rather than general-purpose timers for GUI-related tasks because Swing timers all share the same, pre-existing timer thread and the GUI-related task automatically executes on the event-dispatch thread.
Also See: Concurrency in Swing
Try adding repaint() right after you set the text.
After changing the look of something on screen, you must always repaint the frame.
jLabel1.setText("in show()"); //it does not work
repaint(); //now it works
System.out.println("in show()"); //it works

Doing Live/Dynamic changes in Swing

I am making a game having squares in it (a grid of panels) and when the game ends there is an algorithm that changes the color of the panels one by one in a "live" fashion where the user watches the squares change color slowly. I try something like:
Thread.sleep(1000);
grid.getComponent(boxNumber).setBackground(Color.YELLOW);
Thread.sleep(1000);
grid.getComponent(boxNumber).setBackground(Color.ORANGE);
Although the color of a box changes to Yellow, it does not change to Orange afterwards. Anyone have any ideas? Hope I was able to be clear.
Read the section from the Swing tutorial on Concurrency to understand why you should not be using the sleep() method.
One solution is to use a SwingWorker, then you can 'publish' the color of the component so it can be updated properly on the EDT and you can invoke the sleep() method in the worker as well.
These need to happen on the Swing event thread. call set background via:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
grid.getComponent(boxNumber).setBackground(Color.ORANGE);
}
});
Note, your Thread.sleep() should not be in the event thread (or directly from within a Swing event listener (ActionListener, WindowListener, etc).
It would also be prudent to look the Swing Timing Framework which is specifically for things like this.
-Generally its not a good idea to do Thread.sleep(1000); in the EDT. You should try using Timers.
-You also need to call revalidate()/validate() and repaint() afterward.
So maybe something like this:
Timer yellowTimer = new Timer(1000,new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
jtp.setBackground(Color.YELLOW);
//call revalidate()/validate() and repaint() afterward
jtp.revalidate();
jtp.repaint();
}
});
yellowTimer.setRepeats(false);
Timer orangeTimer = new Timer(2000,new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
jtp.setBackground(Color.ORANGE);
//call revalidate()/validate() and repaint() afterward
jtp.revalidate();
jtp.repaint();
}
});
orangeTimer.setRepeats(false);
yellowTimer.start();
orangeTimer.start();

Categories

Resources