Java Timer Countdown from certain time - java

using Java and Java Swing for a GUI. The scenario is that I want a user to enter in a desired time (in a JTextbox) in the format of HH:MM:SS and from that given time, countdown by seconds until it hits zero.
Currently I am using a timer and the timer.between function. I create an Instant() from the user input time and also use instant.now().
The instants are being created, however, the countdown clock doesn't count down from the user input time, but rather some random numbers that I can't figure out where they are coming from. Can anyone else see the problem?
javax.swing.Timer countDown = new javax.swing.Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Duration countingDown = Duration.between(Instant.now(), userInputCountDown);
autoShutOffTF.setText(String.format("%02d:%02d:%02d",
countingDown.toHours(),
countingDown.toMinutes() % 60,
countingDown.getSeconds() % 60));
}
});
startButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Getting user input, parsing String in the form of HH:MM:SS
String countdownInput = autoShutOffTF.getText();
String getHours = countdownInput.substring(0,2);
int hours = Integer.parseInt(getHours);
String getMins = countdownInput.substring(3,5);
int mins = Integer.parseInt(getMins);
String getSecs = countdownInput.substring(6,8);
int seconds = Integer.parseInt(getSecs);
//Creating a date instance, to get the current year, month and date
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
//creating a new calendar with all of the data
Calendar cal = Calendar.getInstance();
cal.set(year, month, day, hours, mins, seconds);
//creating a new instant with the new calendar with all of the data
userInputCountDown = cal.toInstant();
//starting timer
countDown.start();
}
});

Don't use Date or Calendar, the java.time API is more the capable of achieving what you want.
Looking at this...
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
//creating a new calendar with all of the data
Calendar cal = Calendar.getInstance();
cal.set(year, month, day, hours, mins, seconds);
You're creating a new time, based on the hours/mins/seconds, but, what worries me is, is what happens if the time is less than now? This "might" be the issue you're having.
So, some thing you might want to do is verify if the time is before or after the current time and roll the day accordingly - assuming you want to use an absolute time (ie create a timer which counts down from now to 6pm)
This...
Duration countingDown = Duration.between(Instant.now(), userInputCountDown);
also seems off to me, as userInputCountDown should be in the future
The following example takes a slightly different approach, as it creates a "timer" that will create a target in the future (based on the input) from the current time (adding the hours, mins and seconds) and use it as the anchor point for the count down.
So, you might say, "create a 1 hour" timer, for example.
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextField targetHours;
private JTextField targetMins;
private JTextField targetSeconds;
private Instant futureTime;
private Timer timer;
private JLabel countDown;
public TestPane() {
setLayout(new GridBagLayout());
targetHours = new JTextField("00", 2);
targetMins = new JTextField("00", 2);
targetSeconds = new JTextField("00", 2);
JPanel targetPane = new JPanel(new GridBagLayout());
targetPane.add(targetHours);
targetPane.add(new JLabel(":"));
targetPane.add(targetMins);
targetPane.add(new JLabel(":"));
targetPane.add(targetSeconds);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(8, 8, 8, 8);
add(targetPane, gbc);
JButton btn = new JButton("Start");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
futureTime = LocalDateTime.now()
.plusHours(Long.parseLong(targetHours.getText()))
.plusMinutes(Long.parseLong(targetMins.getText()))
.plusSeconds(Long.parseLong(targetSeconds.getText()))
.atZone(ZoneId.systemDefault()).toInstant();
if (timer != null) {
timer.stop();
}
countDown.setText("---");
timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Duration duration = Duration.between(Instant.now(), futureTime);
if (duration.isNegative()) {
timer.stop();
timer = null;
countDown.setText("00:00:00");
} else {
String formatted = String.format("%02d:%02d:%02d", duration.toHours(), duration.toMinutesPart(), duration.toSecondsPart());
countDown.setText(formatted);
}
}
});
timer.start();
}
});
add(btn, gbc);
countDown = new JLabel("---");
add(countDown, gbc);
}
}
}
WARNING - I do NO validation on the input, so you will have to be careful.
If, instead, you wanted to count down to a particular point in time (ie count down from now to 6pm), then you would need to use LocalDateTime#withHour(Long)#withMinute(Long)#withSecond(Long) chain instead. But, beware, you'll have to verify if the time is in the future or past and take appropriate action, because if you want to countdown to 6pm, but it's 7pm ... what does that actually mean :/ ?

Related

How to get selected item on Jcalendar

I load my jCalendar to Calendar then I used the day for the index but problem every month's days different so I can't select. When I click 21, I'm selecting 10.
Calendar cal = Calendar.getInstance();
cal.setTime(jCalendar1.getDate());
int day = cal.get(Calendar.DAY_OF_MONTH);
JPanel jpanel = jCalendar1.getDayChooser().getDayPanel();
Component compo[] = jpanel.getComponents();
compo[day].setBackground(Color.red);
public class CalendarTest2 extends JFrame {
private static final long serialVersionUID = 1L;
public CalendarTest2() {
Calendar cal = Calendar.getInstance();
JCalendar jCalendar1 = new JCalendar();
cal.setTime(jCalendar1.getDate());
int dayToBeSelected = cal.get(Calendar.DAY_OF_MONTH);
dayToBeSelected = 21;
JPanel jpanel = jCalendar1.getDayChooser().getDayPanel();
Component compo[] = jpanel.getComponents();
for (Component comp : compo) {
if (!(comp instanceof JButton))
continue;
JButton btn = (JButton) comp;
if (btn.getText().equals(String.valueOf(dayToBeSelected)))
comp.setBackground(Color.red);
}
add(jpanel);
}
public static void main(String[] args) {
CalendarTest2 test = new CalendarTest2();
test.setVisible(true);
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.setSize(800, 800);
}
}
Instead of accessing the 'button to be selected' through index,
try to access the button through the text(day number) written on it.
The reason is, calendar of a month is displayed using 49 buttons arranged in 7x7 fashion .
So for ex) index 0 will always point to 'Sunday' button.

Timer Delay method for Creating Stop Watch in Java

Hi I am trying to create a StopWatch app for one of the project questions in the Java Foundations Textbook. So far I have written this code:
package StopWatch;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class StopWatchPanel extends JPanel{
private JPanel userPanel = new JPanel();
private JLabel timeDisplay = new JLabel("00:00:00", SwingConstants.CENTER);
private JButton startButton = new JButton("Start");
private JButton stopButton = new JButton("Stop");
private JButton resetButton = new JButton("Reset");
private Timer refreshRate = new Timer(1, new ActionListen());
private int milliseconds, seconds, minutes, hours;
public StopWatchPanel(){
// user panel settings
userPanel.setPreferredSize(new Dimension(400, 100));
userPanel.setBackground(new Color(200, 200, 255));
// add listeners
startButton.addActionListener(new ActionListen());
stopButton.addActionListener(new ActionListen());
resetButton.addActionListener(new ActionListen());
// component setting
timeDisplay.setPreferredSize(new Dimension(400, 50));
// add components
userPanel.add(timeDisplay);
userPanel.add(startButton);
userPanel.add(stopButton);
userPanel.add(resetButton);
// add to main frame
add(userPanel);
}
private int milsec(){
if(milliseconds > 1000){
milliseconds = 0;
seconds++;
}
return milliseconds++;
}
private int sec(){
if(seconds > 59){
seconds = 0;
minutes++;
}
return seconds;
}
private int min(){
if(minutes > 59){
minutes = 0;
hours++;
}
return minutes;
}
private int hrs(){
if(hours > 23){
hours = 0;
}
return hours;
}
private class ActionListen implements ActionListener{
public void actionPerformed(ActionEvent e){
if(e.getSource().equals(startButton)){
refreshRate.start();
}
else if(e.getSource().equals(refreshRate)){
timeDisplay.setText(sec()+":"+milsec());
}
else if(e.getSource().equals(stopButton)){
refreshRate.stop();
}
else if(e.getSource().equals(resetButton)){
timeDisplay.setText("00:00:00");
milliseconds = 0;
seconds = 0;
minutes = 0;
hours = 0;
}
}
}
}
it works if i set the delay on the timer to 1000ms therefore showing seconds (if i exclude the milsec method) but i want to display milliseconds as well. So I put delay to 1ms so that after each 1ms, it will setText to current count of second (sec method).
But for some reason this doesnt work because the numbers add up too slowly considering that 1000 milliseconds = 1 second.
What am i doing wrong?
The delay of 1 ms means that the timer will generate events every 1 millisecond. The events are then dispatched to the event dispatch thread, which introduces a delay (since there's other code also running on the event dispatch thread), so the actual interval between the calls to actionPerformed() is likely to be larger than 1 ms.
If you need your clock to be precise, you need to measure the exact elapsed time between calls (using, for example, the System.currentTimeMillis() method), rather than increment the time by 1 ms on every call.
You can improve the timeliness of the output by varying the millisecond interval. Instead of 1ms, you can try 10, 20 or 50ms interval. The code below uses 100ms.
package StopWatch;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class StopWatchPanel extends JPanel {
private JPanel userPanel = new JPanel();
private JLabel timeDisplay = new JLabel("00:00:00", SwingConstants.CENTER);
private JButton startButton = new JButton("Start");
private JButton stopButton = new JButton("Stop");
private JButton resetButton = new JButton("Reset");
private Timer refreshRate = new Timer(100, new ActionListen());
private int milliseconds, seconds, minutes, hours;
public StopWatchPanel(){
// user panel settings
userPanel.setPreferredSize(new Dimension(400, 100));
userPanel.setBackground(new Color(200, 200, 255));
// add listeners
startButton.addActionListener(new ActionListen());
stopButton.addActionListener(new ActionListen());
resetButton.addActionListener(new ActionListen());
// component setting
timeDisplay.setPreferredSize(new Dimension(400, 50));
// add components
userPanel.add(timeDisplay);
userPanel.add(startButton);
userPanel.add(stopButton);
userPanel.add(resetButton);
// add to main frame
add(userPanel);
}
private int milsec(){
milliseconds+=100;
if(milliseconds >= 1000){
milliseconds = 0;
seconds++;
}
return milliseconds;
}
private int sec(){
if(seconds > 59){
seconds = 0;
minutes++;
}
return seconds;
}
private int min(){
if(minutes > 59){
minutes = 0;
hours++;
}
return minutes;
}
private int hrs(){
if(hours > 23){
hours = 0;
}
return hours;
}
private class ActionListen implements ActionListener{
public void actionPerformed(ActionEvent e){
if(e.getSource().equals(startButton)){
refreshRate.start();
}
else if(e.getSource().equals(refreshRate)){
int tms = milsec();
int tsec = sec();
int tmin = min();
int thr = hrs();
timeDisplay.setText(thr + ":" +tmin+ ":" +tsec+ "." +tms/100);
}
else if(e.getSource().equals(stopButton)){
refreshRate.stop();
}
else if(e.getSource().equals(resetButton)){
timeDisplay.setText("00:00:00");
milliseconds = 0;
seconds = 0;
minutes = 0;
hours = 0;
}
}
}
}
I believe the original code was primarily made for demo purposes and does not concern too much on the accurateness of the time. If you want a more realtime output, you will need to try a different approach. In such case you may use the System.currentTimeMillis() as pointed out by the other answer.

Time Difference between events

I am trying to calculate the time difference between the user-set-date and the current-system-date.
My code is as follows,
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args){
// Make the frame
JFrame appFrame = new JFrame("Get Things Done");
// Make a panel
WelcomePanel buttonPanel = new WelcomePanel();
// Set the class button to work
appFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Add the panel to the frame
appFrame.add(buttonPanel);
// Set the size of the frame
appFrame.setSize(400, 400);
// Make the frame visible
appFrame.setVisible(true);
appFrame.pack();
WelcomePanel welcome = new WelcomePanel();
// --------------------------------------------------------------------------
// Print currentTime
Time time = new Time();
time.printCurrentTime();
UserEvent input = new UserEvent();
// Test inputTime
input.setInputTime("15/05/28 18:00:00");
System.out.println("***Test Getters and Setters***");
System.out.println(input.getInputTime());
} // end main
} // end class
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Time {
Date currentDate = new Date();
UserEvent user = new UserEvent();
// Print current time
public void printCurrentTime(){
DateFormat dateFormat = new SimpleDateFormat ("yy/MM/dd HH:mm:ss");
// System.out.println("date without format: "+ currentDate.toString());
System.out.println(dateFormat.format(currentDate));
} // end printCurrentTime
public long getCurrentTime(){
return currentDate.getTime();
}
// ----------------------------------------------------------------------------
} // end class
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class UserEvent {
private String inputTime;
Date user = new Date();
// set inputTime
public void setInputTime(String newInputTime){
inputTime = newInputTime;
} // end setInputTime
// get inputTime
public String getInputTime(){
return inputTime;
} // end getInputTime
public void parseInput(){
DateFormat dateFormat = new SimpleDateFormat ("yy/MM/dd HH:mm:ss");
try{
user = dateFormat.parse(inputTime);
System.out.println(user);
} catch (ParseException error){
System.out.println("Are you sure you entered a date?");
} // end try/catch
}
// ---------------------------------------------------------------------------
}
I have been searching for lots and lots of examples, but still no progress on my code.
public static void main(String[] argv) throws InterruptedException // Thread.sleep throws that
{
Random rng = new Random();
Date start = new Date();
Thread.sleep(rng.nextInt(1000)); // sleep for 0-999 ms
Date end = new Date();
System.out.println("Slept for " + (end.getTime() - start.getTime()) + "ms.");
}
Possible output is: Slept for 590ms.
You can try it yourself here.

why does it always give the same time?

I used the following program to get the clock.What it turned out to be is a static clock ? Why is it so ?
import java.util.*;
import java.awt.*;
import javax.swing.*;
class tester {
JFrame fr = new JFrame();
JPanel p = new JPanel();
JLabel l = new JLabel();
Date d = new Date();
GregorianCalendar gc = new GregorianCalendar();
tester() {
p.setBackground(Color.red);
l.setVisible(true);
p.add(l);
fr.add(p);
fr.setSize(200,200);
fr.setVisible(true);
startClockThread();
}
public void startClockThread() {
Runnable r = new Runnable() {
#Override
public void run() {
startClock();
}
};
new Thread(r).start();
}
public void startClock() {
l.setVisible(true);
while(true) {
l.setText(gc.get(gc.HOUR) + ":" + gc.get(gc.MINUTE) + ":" + gc.get(gc.SECOND));
System.out.println(gc.get(gc.SECOND));
}
}
public static void main(String args[]) {
new tester();
}
}
GregorianCalendar() Constructs a default GregorianCalendar using the current time in the default time zone with the default locale. Java Doc
You can do this way.
while(true) {
GregorianCalendar gc = new GregorianCalendar();
l.setText(gc.get(gc.HOUR) + ":" + gc.get(gc.MINUTE) + ":" + gc.get(gc.SECOND));
}
Now you should understand why you are getting a static clock !
You only create the GregorianCalendar once, and it never gets updated. So the date is always the same.
there's are big problems apart from the one you have spotted:
dont let threads run wild, they'll freeze the ui eventually
each and every access to a Swing component must happen on the EDT
You can solve both easiest by using a javax.swing.Timer
ActionListener nextSecond = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// get time ...
timeLabel.setText(...);
}
}
new Timer(1000, nextSecond).start();

Is there any good and free Date AND Time Picker available for Java Swing? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking us to recommend or find a tool, library or favorite off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it.
Closed 9 years ago.
Improve this question
Is there any good and free Date AND Time Picker available for Java Swing?
There are a lot date pickers available but no date AND time picker. This is the closest I came across so far: Looking for a date AND time picker
Anybody?
For a time picker you can use a JSpinner and set a JSpinner.DateEditor that only shows the time value.
JSpinner timeSpinner = new JSpinner( new SpinnerDateModel() );
JSpinner.DateEditor timeEditor = new JSpinner.DateEditor(timeSpinner, "HH:mm:ss");
timeSpinner.setEditor(timeEditor);
timeSpinner.setValue(new Date()); // will only show the current time
You can extend the swingx JXDatePicker component:
"JXDatePicker only handles dates without time. Quite often we need to let the user choose a date and a time. This is an example of how to make use JXDatePicker to handle date and time together."
http://wiki.java.net/twiki/bin/view/Javadesktop/JXDateTimePicker
EDIT: This article disappeared from the web, but as SingleShot discovered, it is still available in an internet archive. Just to be sure, here is the full working example:
import org.jdesktop.swingx.calendar.SingleDaySelectionModel;
import org.jdesktop.swingx.JXDatePicker;
import javax.swing.*;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.DateFormatter;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.*;
import java.awt.*;
/**
* This is licensed under LGPL. License can be found here: http://www.gnu.org/licenses/lgpl-3.0.txt
*
* This is provided as is. If you have questions please direct them to charlie.hubbard at gmail dot you know what.
*/
public class DateTimePicker extends JXDatePicker {
private JSpinner timeSpinner;
private JPanel timePanel;
private DateFormat timeFormat;
public DateTimePicker() {
super();
getMonthView().setSelectionModel(new SingleDaySelectionModel());
}
public DateTimePicker( Date d ) {
this();
setDate(d);
}
public void commitEdit() throws ParseException {
commitTime();
super.commitEdit();
}
public void cancelEdit() {
super.cancelEdit();
setTimeSpinners();
}
#Override
public JPanel getLinkPanel() {
super.getLinkPanel();
if( timePanel == null ) {
timePanel = createTimePanel();
}
setTimeSpinners();
return timePanel;
}
private JPanel createTimePanel() {
JPanel newPanel = new JPanel();
newPanel.setLayout(new FlowLayout());
//newPanel.add(panelOriginal);
SpinnerDateModel dateModel = new SpinnerDateModel();
timeSpinner = new JSpinner(dateModel);
if( timeFormat == null ) timeFormat = DateFormat.getTimeInstance( DateFormat.SHORT );
updateTextFieldFormat();
newPanel.add(new JLabel( "Time:" ) );
newPanel.add(timeSpinner);
newPanel.setBackground(Color.WHITE);
return newPanel;
}
private void updateTextFieldFormat() {
if( timeSpinner == null ) return;
JFormattedTextField tf = ((JSpinner.DefaultEditor) timeSpinner.getEditor()).getTextField();
DefaultFormatterFactory factory = (DefaultFormatterFactory) tf.getFormatterFactory();
DateFormatter formatter = (DateFormatter) factory.getDefaultFormatter();
// Change the date format to only show the hours
formatter.setFormat( timeFormat );
}
private void commitTime() {
Date date = getDate();
if (date != null) {
Date time = (Date) timeSpinner.getValue();
GregorianCalendar timeCalendar = new GregorianCalendar();
timeCalendar.setTime( time );
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, timeCalendar.get( Calendar.HOUR_OF_DAY ) );
calendar.set(Calendar.MINUTE, timeCalendar.get( Calendar.MINUTE ) );
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Date newDate = calendar.getTime();
setDate(newDate);
}
}
private void setTimeSpinners() {
Date date = getDate();
if (date != null) {
timeSpinner.setValue( date );
}
}
public DateFormat getTimeFormat() {
return timeFormat;
}
public void setTimeFormat(DateFormat timeFormat) {
this.timeFormat = timeFormat;
updateTextFieldFormat();
}
public static void main(String[] args) {
Date date = new Date();
JFrame frame = new JFrame();
frame.setTitle("Date Time Picker");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DateTimePicker dateTimePicker = new DateTimePicker();
dateTimePicker.setFormats( DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.MEDIUM ) );
dateTimePicker.setTimeFormat( DateFormat.getTimeInstance( DateFormat.MEDIUM ) );
dateTimePicker.setDate(date);
frame.getContentPane().add(dateTimePicker);
frame.pack();
frame.setVisible(true);
}
}
Use the both combined.. that's what i did:
public static JPanel buildDatePanel(String label, Date value) {
JPanel datePanel = new JPanel();
JDateChooser dateChooser = new JDateChooser();
if (value != null) {
dateChooser.setDate(value);
}
for (Component comp : dateChooser.getComponents()) {
if (comp instanceof JTextField) {
((JTextField) comp).setColumns(50);
((JTextField) comp).setEditable(false);
}
}
datePanel.add(dateChooser);
SpinnerModel model = new SpinnerDateModel();
JSpinner timeSpinner = new JSpinner(model);
JComponent editor = new JSpinner.DateEditor(timeSpinner, "HH:mm:ss");
timeSpinner.setEditor(editor);
if(value != null) {
timeSpinner.setValue(value);
}
datePanel.add(timeSpinner);
return datePanel;
}
There is the FLib-JCalendar component with a combined Date and Time Picker.
As you said Date picker is easy, there are many out there.
As for a Time picker, check out how Google Calendar does it when creating a new entry. It allows you to type in anything while at the same time it has a drop down in 30 mins increments. The drop down changes when you change the minutes.
If you need to allow the user to pick seconds, then the best you can do is a typable/drop down combo

Categories