I want to implement a clock within my program to diusplay the date and time while the program is running. I have looked into the getCurrentTime() method and Timers but none of them seem to do what I would like.
The problem is I can get the current time when the program loads but it never updates. Any suggestions on something to look into would be greatly appreciated!
What you need to do is use Swing's Timer class.
Just have it run every second and update the clock with the current time.
Timer t = new Timer(1000, updateClockAction);
t.start();
This will cause the updateClockAction to fire once a second. It will run on the EDT.
You can make the updateClockAction similar to the following:
ActionListener updateClockAction = new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Assumes clock is a custom component
yourClock.setTime(System.currentTimeMillis());
// OR
// Assumes clock is a JLabel
yourClock.setText(new Date().toString());
}
}
Because this updates the clock every second, the clock will be off by 999ms in a worse case scenario. To increase this to a worse case error margin of 99ms, you can increase the update frequency:
Timer t = new Timer(100, updateClockAction);
You have to update the text in a separate thread every second.
Ideally you should update swing component only in the EDT ( event dispatcher thread ) but, after I tried it on my machine, using Timer.scheduleAtFixRate gave me better results:
java.util.Timer http://img175.imageshack.us/img175/8876/capturadepantalla201006o.png
The javax.swing.Timer version was always about half second behind:
javax.swing.Timer http://img241.imageshack.us/img241/2599/capturadepantalla201006.png
I really don't know why.
Here's the full source:
package clock;
import javax.swing.*;
import java.util.*;
import java.text.SimpleDateFormat;
class Clock {
private final JLabel time = new JLabel();
private final SimpleDateFormat sdf = new SimpleDateFormat("hh:mm");
private int currentSecond;
private Calendar calendar;
public static void main( String [] args ) {
JFrame frame = new JFrame();
Clock clock = new Clock();
frame.add( clock.time );
frame.pack();
frame.setVisible( true );
clock.start();
}
private void reset(){
calendar = Calendar.getInstance();
currentSecond = calendar.get(Calendar.SECOND);
}
public void start(){
reset();
Timer timer = new Timer();
timer.scheduleAtFixedRate( new TimerTask(){
public void run(){
if( currentSecond == 60 ) {
reset();
}
time.setText( String.format("%s:%02d", sdf.format(calendar.getTime()), currentSecond ));
currentSecond++;
}
}, 0, 1000 );
}
}
Here's the modified source using javax.swing.Timer
public void start(){
reset();
Timer timer = new Timer(1000, new ActionListener(){
public void actionPerformed( ActionEvent e ) {
if( currentSecond == 60 ) {
reset();
}
time.setText( String.format("%s:%02d", sdf.format(calendar.getTime()), currentSecond ));
currentSecond++;
}
});
timer.start();
}
Probably I should change the way the string with the date is calculated, but I don't think that's the problem here
I have read, that, since Java 5 the recommended is: ScheduledExecutorService I leave you the task to implement it.
This sounds like you might have a conceptual problem. When you create a new java.util.Date object, it will be initialised to the current time. If you want to implement a clock, you could create a GUI component which constantly creates a new Date object and updates the display with the latest value.
One question you might have is how to repeatedly do something on a schedule? You could have an infinite loop that creates a new Date object then calls Thread.sleep(1000) so that it gets the latest time every second. A more elegant way to do this is to use a TimerTask. Typically, you do something like:
private class MyTimedTask extends TimerTask {
#Override
public void run() {
Date currentDate = new Date();
// Do something with currentDate such as write to a label
}
}
Then, to invoke it, you would do something like:
Timer myTimer = new Timer();
myTimer.schedule(new MyTimedTask (), 0, 1000); // Start immediately, repeat every 1000ms
public void start(){
reset();
ScheduledExecutorService worker = Executors.newScheduledThreadPool(3);
worker.scheduleAtFixedRate( new Runnable(){
public void run(){
if( currentSecond == 60 ) {
reset();
}
time.setText( String.format("%s:%02d", sdf.format(calendar.getTime()), currentSecond));
currentSecond++;
}
}, 0, 1000 ,TimeUnit.MILLISECONDS );
}
For those preferring an analog display: Analog Clock JApplet.
Note the method scheduleAtFixedRate is used here
// Current time label
final JLabel currentTimeLabel = new JLabel();
currentTimeLabel.setFont(new Font("Monospace", Font.PLAIN, 18));
currentTimeLabel.setHorizontalAlignment(JTextField.LEFT);
// Schedule a task for repainting the time
final Timer currentTimeTimer = new Timer();
TimerTask task = new TimerTask() {
#Override
public void run() {
currentTimeLabel.setText(TIME_FORMATTER.print(System.currentTimeMillis()));
}
};
currentTimeTimer.scheduleAtFixedRate(task, 0, 1000);
Timer timer = new Timer(1000, (ActionEvent e) -> {
DateTimeFormatter myTime = DateTimeFormatter.ofPattern("HH:mm:ss");
LocalDateTime now = LocalDateTime.now();
jLabel1.setText(String.valueOf(myTime.format(now)));
});
timer.setRepeats(true);
timer.start();
Related
Trying to make a timer that displays the time that has elapsed since a button has been pressed. I am using a Date instance and am trying to have it be initalized to 00:00:00 and have it increase by seconds, mins, then hours. it works as just a clock of the current time if I do not enter any values into Date currentTime = new date()
Here is my code, I have tried setting the Date to all 0 values, and it displays as all zeros, but when my button is pressed, it no longer functions as a timer. What is the problem?
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Date currentTime = new Date(0,0,0,0,0,0);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
laserOnTimeTF.setText(sdf.format(currentTime));
}
});
laserOnOff.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (!laserSetting) {
timer.start();
laserSetting = true;
laserOnOff.setText("Laser On");
} else {
timer.stop();
laserSetting = false;
laserOnOff.setText("Laser Off");
}
}
});
That Date constructor is deprecated, like all Date constructors other than the one that takes a milliseconds argument. APIs are deprecated for a reason, usually because they don’t work as intended. To be notified when you use deprecated APIs, turn on all compiler warnings in your IDE, and pay attention to those warnings.
Date is not a good fit for storing elapsed time, since it represents an absolute point in time. The class which is designed to represent a time difference is java.time.Duration.
You can calculate a Duration from two time values. The simplest time value is probably Instant, so you will want a private field of type Instant in the class which creates the Timer and adds a listener to the button, to keep track of when the button was pressed:
private Instant timeOfLastButtonPress;
Then you can initialize it each time the button is actually pressed:
laserOnOff.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (!laserSetting) {
timeOfLastButtonPress = Instant.now();
timer.start();
laserSetting = true;
laserOnOff.setText("Laser On");
} else {
timer.stop();
laserSetting = false;
laserOnOff.setText("Laser Off");
}
}
});
Finally, your Timer can calculate the Duration using Duration.between:
Duration elapsedTime =
Duration.between(timeOfLastButtonPress, Instant.now());
If you’re using Java 9 or later, you can extract the numbers from a Duration directly:
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Duration elapsedTime =
Duration.between(timeOfLastButtonPress, Instant.now());
laserOnTimeTF.setText(String.format("%02d:%02d:%02d",
elapsedTime.toHoursPart(),
elapsedTime.toMinutesPart(),
elapsedTime.toSecondsPart()));
}
});
In Java 8, you will need to calculate it yourself:
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Duration elapsedTime =
Duration.between(timeOfLastButtonPress, Instant.now());
laserOnTimeTF.setText(String.format("%02d:%02d:%02d",
elapsedTime.toHours(),
elapsedTime.toMinutes() % 60,
elapsedTime.getSeconds() % 60));
}
});
Hello I would like to ask for any advice on this problem.
I would like to display current time in HH:MM:SS format (refreshing every second) in label or whatever component that is good for it.
Any advice?
EDIT: Someone asked for a code.. so I put it here for better description of the problem. "I have no code for that time What I'm trying to achieve is simple GUI diary and in one of the labels I would like to display time remaining until the closest event and in the other label I want to display like clocks that refreshes every second. I need it to get remaining time working. All I can think of is creating new thread that will do it and refreshes the clock, but I am not that advanced to use multithreading in JavaFX . So I was wondering if anyone can advice me with something less complicated than multithreading (I dont know how to implement that thread into JavaFX components)"
Version with Timeline:
long endTime = ...;
Label timeLabel = new Label();
DateFormat timeFormat = new SimpleDateFormat( "HH:mm:ss" );
final Timeline timeline = new Timeline(
new KeyFrame(
Duration.millis( 500 ),
event -> {
final long diff = endTime - System.currentTimeMillis();
if ( diff < 0 ) {
// timeLabel.setText( "00:00:00" );
timeLabel.setText( timeFormat.format( 0 ) );
} else {
timeLabel.setText( timeFormat.format( diff ) );
}
}
)
);
timeline.setCycleCount( Animation.INDEFINITE );
timeline.play();
Label main_clock_lb = new Label();
Thread timerThread = new Thread(() -> {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
while (true) {
try {
Thread.sleep(1000); //1 second
} catch (InterruptedException e) {
e.printStackTrace();
}
final String time = simpleDateFormat.format(new Date());
Platform.runLater(() -> {
main_clock_lb.setText(time);
});
}
}); timerThread.start();//start the thread and its ok
One might find helpful how to print date and time for javaFx.
final Label clock = new Label();
final DateFormat format = DateFormat.getInstance();
final Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1),
new EventHandler()
{
#Override
public void handle(ActionEvent event)
{
final Calendar cal = Calendar.getInstance();
clock.setText(format.format(cal.getTime());
}
});
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
To solve your task using Timer you need to implement TimerTask with your code and use Timer#scheduleAtFixedRate method to run that code repeatedly:
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
System.out.print("I would be called every 2 seconds");
}
}, 0, 2000);
Also note that calling any UI operations must be done on Swing UI thread (or FX UI thread if you are using JavaFX):
private int i = 0;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
jTextField1.setText(Integer.toString(i++));
}
});
}
}, 0, 2000);
}
In case of JavaFX you need to update FX controls on "FX UI thread" instead of Swing one. To achieve that use javafx.application.Platform#runLater method instead of SwingUtilities
final Label clock = new Label();
final DateFormat format = DateFormat.getInstance();
final Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1),
new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
final Calendar cal = Calendar.getInstance();
clock.setText(format.format(cal.getTime()));
}
}));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
I am using Swing Timer to delay my task for a specific period of time. This time interval is decided by the user.
In my GUI, I have a SpinnerDateModel to accept the time at which the task has to be performed.
SpinnerDateModel date = new SpinnerDateModel();
JSpinner spinner = new JSpinner(date);
frame.getContentPane().add(spinner);
Date futureDate = date.getDate();
Now, Timer has arguments Timer(int delay, ActionListener task)
ActionListener task = new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
//send function
}
};
Timer timer = new Timer(delay, task);
timer.setRepeats(false);
timer.start();
How do I set this delay to the time specified by the user?
With some checking to prevent a negative delay, something like:
delay=Math.max(0,futureDate.getTime()-System.currentTimeMillis());
delay=Math.min(delay,Integer.MAX_VALUE);
// or:
// if(delay>Integer.MAX_VALUE) { throw new exception-of-some-sort }
Timer timer=new Timer((int)delay,task);
should do the trick.
This will calculate the delay based on the number of milliseconds from now until the (presumed future) date selected by the user.
I have this java code using Threads to calculate the time elapsed once the start button is hit till the stop button is not hit.
I want to do this using Threads only
import javax.swing.*;
import java.awt.event.*;
// This will count the elapsed time between running time of two threads.
class ThreadGame {
JButton button;
MyAction my_action;
public static void main(String[] args) {
ThreadGame tg = new ThreadGame();
}
public ThreadGame() {
JFrame frame = new JFrame("Calculate time - Game");
button = new JButton("Start");
button.addActionListener(new MyAction());
frame.add(button);
frame.setSize(400, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class MyAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
String text = (String) e.getActionCommand();
final Timer timer = new Timer();
if (text.equals("Start")) {
button.setText("Stop");
Thread start_time = new Thread() {
public void run() {
timer.startTime();
}
};
start_time.start();
try {
start_time.join();
} catch (Exception e1) {
}
} else {
Thread stop_time = new Thread() {
public void run() {
timer.stopTime();
}
};
Thread get_time = new Thread() {
public void run() {
timer.getElapsedTime();
System.out.println(timer.elapsed);
}
};
stop_time.start();
try {
stop_time.join();
} catch (Exception e2) {
}
get_time.start();
button.setText("Start");
}
}
}
class Timer {
public double startTime = 0.0;
public double stopTime = 0.0;
public boolean running = false;
public double elapsed = 0.0;
public void startTime() {
this.startTime = System.nanoTime();
this.running = true;
}
public void stopTime() {
this.stopTime = System.nanoTime();
this.running = false;
}
// Elasped time in seconds
public double getElapsedTime() {
// double elapsed;
if (running) {
elapsed = ((System.nanoTime() - startTime) / 1000);
} else {
elapsed = ((stopTime - startTime) / 1000);
}
return elapsed;
}
}
}
EDIT: I have understand the problem: timer scope was the problem.
EDIT 2: Ok, it looks like I have to use suspend and resume in one thread only.
The problem is that the start button press is starting a different Timer object than the stop-button button press is stopping because the Timer object is created every time when the actionPerformed(...) method is called.
The Timer needs to be a field in your MyAction class. You also don't need all of the thread start/joins because the Timer object is very simple and fast.
Really, you can just use a startTimeMillis long field instead of a timer. Something like:
class MyAction implements ActionListener {
private long startTimeMillis;
public void actionPerformed(ActionEvent e) {
String text = (String) e.getActionCommand();
if (text.equals("Start")) {
startTimeMillis = System.currentTimeMillis();
...
} else {
System.out.println(System.currentTimeMillis() - startTimeMillis);
}
}
}
Your problem is caused by the scope of timer. This should be a private instance variable, not a local method variable. Further, wrapping calls to startTime and endTime in a thread's run method isn't gaining you anything, because these are incredibly short-lived calls. But that's not the real problem here.
There's no reason to be running Timer in its own thread. That is, without using a specialized real-time operating system, using threads to solve the problem of measuring the duration between two events is just plain wrong.
You might think that you could create a thread with a loop that increments a msec variable after a Thread.sleep(1). Don't do this! This kind of timing is also just plain wrong. Your computer uses a preemptive multitasking model which means there's no guarantee that your thread will execute on a regular interval. That is, there is nothing requiring that Thread.sleep(1) will sleep for some maximum duration. The guarantee is that your thread will sleep for a minimum of 1ms. This means there's no way to determine clock error if you're managing a clock yourself in software, and this error is not insignificant. Just don't do it!! Time should always be measured by your operating system, preferably using an interrupt-based timer (which is how System.nanoTime works on most, if not all platforms).
Instead of using a thread, just call your startTime and stopTime methods directly from your original thread.
Try this:
class ThreadGame {
JButton button;
MyAction my_action;
private final Timer timer = new Timer();
public static void main(String[] args) {
ThreadGame tg = new ThreadGame();
}
public ThreadGame() {
JFrame frame = new JFrame("Calculate time - Game");
button = new JButton("Start");
button.addActionListener(new MyAction());
frame.add(button);
frame.setSize(400, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class MyAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
String text = (String) e.getActionCommand();
if (text.equals("Start")) {
timer.startTime();
button.setText("Stop");
} else {
timer.stopTime();
button.setText("Start");
}
}
}
class Timer {
public double startTime = 0.0;
public double stopTime = 0.0;
public boolean running = false;
public double elapsed = 0.0;
public void startTime() {
this.startTime = System.nanoTime();
this.running = true;
}
public void stopTime() {
this.stopTime = System.nanoTime();
this.running = false;
}
// Elasped time in seconds
public double getElapsedTime() {
return (this.startTime-this.stopTime)*1000000000.0;
}
}
}
If you want to learn how to use threads, try writing an application that solves a problem for which threads are a good fit. For example, write a small Swing application that lets you download a file from the web. As the file is downloading, update a progress bar in your UI. The download should happen in a worker thread separately from the UI thread, otherwise the UI will block during the download's progress.
Another example problem is to write a threaded ray tracer (here's an example tutorial written in C++).
If you want something simpler, write a Swing clock. Use a loop within a separate thread to update the UI at a periodic interval, but do not use the loop to manage what time it is. Again, don't try to keep time in the loop, just let the OS keep the time, and use the loop to schedule when the UI gets updated with the current OS time.
You're never calling getElapsedTime() that updates elapsed field.
You are creating a new Timer when ever you click the button. Make timer a class variable of your MyAction
The code below should be sufficient to get elapsed time.
class MyAction implements ActionListener {
final Timer timer = new Timer();
public void actionPerformed(ActionEvent e) {
String text = (String) e.getActionCommand();
if (text.equals("Start")) {
button.setText("Stop");
timer.startTime();
} else {
timer.stopTime();
System.out.println(timer.elapsed);
button.setText("Start");
}
}
}
Simply do this...
- Call System.currentTimeMillis() at the Starting of threads.
- Then again call System.currentTimeMillis() at the end of threads.
- Subtract the end with starting value to get the Elapsed time...
/////////////////EDITED///////////////////////
Make sure that the method trying to manipulate(ie. read and write) the variable holding the System.currentTimeMillis() must be synchronized, with synchronized keyword, so that Race Condition doesn't occur according to Brian's Law...
If you are writing a variable that might next be read by another thread, or reading a variable that might have last been written by another thread, you must use synchronization, and further, both the reader and the writer must synchronize using the same monitor lock.
I've written a TimerTask to display current date and time in a JLabel. Following is the TimerTask code and that works well in normal scenario. When I change the system date and time when the GUI is running, the timer stops running. There was no exception when I changed system date and time and the Timer just stops running.
Can anyone tell me what is happening?
private void startTimer()
{
// Start the clock
timer = new Timer();
timer.schedule(new TimeTask(), 0, 1000);
}
class TimeTask extends TimerTask
{
public void run()
{
try {
clockLabel.setText(new SimpleDateFormat("EEE , dd MMM , HH:mm:ss").format(Calendar.getInstance().getTime()));
System.out.println(clockLabel.getText());
} catch(Exception ex) {
ex.printStackTrace();
System.out.println("Exception : " + ex.getMessage());
}
}
}
Don't use TimerTask with Swing as you can easily run into concurrency issues as TimerTask will be calling code off of the EDT. Instead use a Swing Timer; this is specifically what it is built for -- calling code periodically on the Swing event thread.
i.e.,
private void startTimer() {
timer = new Timer(TIMER_DELAY, new TimerListener());
timer.start();
}
private class TimerListener implements ActionListener {
private final String PATTERN = "EEE , dd MMM , HH:mm:ss";
private final DateFormat S_DATE_FORMAT = new SimpleDateFormat(PATTERN);
#Override
public void actionPerformed(ActionEvent e) {
Date date = Calendar.getInstance().getTime();
String dateString = S_DATE_FORMAT.format(date);
clockLabel.setText(dateString);
}
}
you have got issues with Concurency in Swing, where output from java.util.Timer doesn't invoke EventDispatchThread and represents Backgroung task for Swing GUI,
since will be better to use Swing Timer, because guarantee the output will be on EDT, but Swing Timer isn't accurate for long running taks in compare with java.util.Timer,
for updating Swing GUI from any type of background tasks you have to wrap output to the Swing GUI into invokeLater
for example
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JLabel#setText();
}
});