Reputation:
I've tried to write a litte java-program that should work as a timer.
The problem is (probably) that I need to use Thread.sleep()
, which throws InterruptedException
. So if I start the program, I am able to enter the seconds an minutes, but when pressing "OK", nothing happens (it also doesn't show any warnings or errors in the terminal).
Here's the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import javax.swing.text.NumberFormatter;
import static javax.swing.WindowConstants.EXIT_ON_CLOSE;
public class Timer {
public static void main(String[] args) throws InterruptedException {
SwingUtilities.invokeLater(Timer::new);
}
private JButton button;
private JTextField minutes;
private JTextField seconds;
Timer() {
JFrame frame = new JFrame();
frame.setSize(300, 200);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel panel = new JPanel(new BorderLayout());
JPanel subpanel1 = new JPanel(new GridLayout(1, 2));
/*
* The following lines ensure that the user can
* only enter numbers.
*/
NumberFormat format = NumberFormat.getInstance();
NumberFormatter formatter = new NumberFormatter(format);
formatter.setValueClass(Integer.class);
formatter.setMinimum(0);
formatter.setMaximum(Integer.MAX_VALUE);
formatter.setAllowsInvalid(false);
formatter.setCommitsOnValidEdit(true);
minutes = new JFormattedTextField(formatter);
seconds = new JFormattedTextField(formatter);
minutes.setText("0");
seconds.setText("0");
JPanel subpanel2 = new JPanel();
/*
* When the user presses the OK-button, the program will
* start to count down.
*/
button = new JButton("OK");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
try {
timer();
}
catch(InterruptedException e) {
}
}
});
JButton button2 = new JButton("Reset");
button2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
minutes.setText("0");
seconds.setText("0");
button.setEnabled(true);
}
});
subpanel1.add(minutes);
subpanel1.add(seconds);
subpanel2.add(button);
subpanel2.add(button2);
panel.add(subpanel1, BorderLayout.CENTER);
panel.add(subpanel2, BorderLayout.PAGE_END);
frame.add(panel);
frame.setVisible(true);
}
//Method for the timer
void timer() throws InterruptedException {
int min = Integer.valueOf(minutes.getText());
int sec = Integer.valueOf(seconds.getText());
button.setEnabled(false);
while(min > 0 || sec > 0) {
Thread.sleep(1000);
if(sec >= 1) {
sec = sec - 1;
seconds.setText(String.valueOf(sec));
}
else if(sec == 0 || min > 0) {
sec = 59;
min = min - 1;
seconds.setText(String.valueOf(sec));
minutes.setText(String.valueOf(min));
}
}
}
}
What can I do to make it work?
I know replaced Thread.sleep()
with the following:
Timer timer = new Timer(delay, taskPerformer);
timer.setRepeats( false );
timer.start();
Now an error occurs: The constructor cannot applied to given types (it wants no arguments). What did I do wrong? (The variables delay and taskPerformer are defined, and I did not import java.util.Timer)
Upvotes: 1
Views: 575
Reputation: 18812
The following mre shows how you can use javax.swing.Timer
to get the desired countdown :
import static javax.swing.WindowConstants.EXIT_ON_CLOSE;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.text.NumberFormat;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.text.NumberFormatter;
public class MyTimer {
public static void main(String[] args) throws InterruptedException {
SwingUtilities.invokeLater(MyTimer::new);
}
private final JButton startButton, resetButton;
private final JTextField minutes;
private final JTextField seconds;
private static final int SECOND = 1000;
private Timer timer;
MyTimer() {
JFrame frame = new JFrame();
//frame.setSize(300, 200);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
/*
* The following lines ensure that the user can
* only enter numbers.
*/
NumberFormat format = NumberFormat.getInstance();
NumberFormatter formatter = new NumberFormatter(format);
formatter.setValueClass(Integer.class);
formatter.setMinimum(0);
formatter.setMaximum(Integer.MAX_VALUE);
formatter.setAllowsInvalid(false);
formatter.setCommitsOnValidEdit(true);
minutes = new JFormattedTextField(formatter);
seconds = new JFormattedTextField(formatter);
minutes.setText("0");
seconds.setText("0");
/*
* When the user presses the OK-button, the program will
* start to count down.
*/
startButton = new JButton("OK");
startButton.addActionListener(actionEvent -> {
timer();
});
resetButton = new JButton("Reset");
resetButton.setEnabled(false);
resetButton.addActionListener(actionEvent -> {
reset();
});
JPanel subpanel1 = new JPanel(new GridLayout(1, 2));
subpanel1.add(minutes);
subpanel1.add(seconds);
JPanel subpanel2 = new JPanel();
subpanel2.add(startButton);
subpanel2.add(resetButton);
JPanel panel = new JPanel(new BorderLayout());
panel.add(subpanel1, BorderLayout.CENTER);
panel.add(subpanel2, BorderLayout.PAGE_END);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
void timer() {
startButton.setEnabled(false);
timer = new Timer(SECOND, e->{
final int min = Integer.valueOf(minutes.getText());
final int sec = Integer.valueOf(seconds.getText());
if(sec == 0 && min == 0){
reset();
}else if(sec >= 1) {
seconds.setText(String.valueOf(sec-1));
}
else if(sec == 0 || min > 0) {
seconds.setText(String.valueOf(59));
minutes.setText(String.valueOf(min-1));
}
});
timer.setRepeats(true);
timer.start();
resetButton.setEnabled(true);
}
private void reset() {
if(timer != null) {
timer.stop();
}
minutes.setText("0");
seconds.setText("0");
startButton.setEnabled(true);
}
}
Upvotes: 1
Reputation: 17
Since you need the timer only for showing hours, you could simply create a new thread to handle that, leaving the main thread to handle other stuff like user IO.
Upvotes: 0