Это как для OP, так и для Perry Monschau: это пример «рабочего» Swing Timer, который запускается и останавливается по команде.Я еще не закончил с этой программой, поскольку пытаюсь сделать ее более похожей на MVC, но, тем не менее, запустите ее, и вы увидите, что она работает нормально.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.*;
@SuppressWarnings("serial")
public class CountDownTimer extends JPanel {
private static final int BL_GAP = 5;
private static final int MS_PER_SEC = 1000;
private static final int SEC_PER_MIN = 60;
private static final int MIN_PER_HR = 60;
private static final float DISPLAY_PTS = 54f;
private static final String DISPLAY_FORMAT_STR = "%02d:%02d:%02d:%01d";
private static final float SPINNER_FONT_PTS = 16f;
public static final int TIMER_DELAY = 50;
public static final Color NEGATIVE_COLOR = Color.red;
private StartAction startAction = new StartAction();
private ResetAction resetAction = new ResetAction(startAction);
private QuitAction quitAction = new QuitAction();
private final Action[] btnActions = { resetAction , startAction ,
quitAction };
private JSpinner hourSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 10,
1));
private JSpinner minuteSpinner = new JSpinner(new SpinnerNumberModel(0, 0,
60, 1));
private JSpinner secondSpinner = new JSpinner(new SpinnerNumberModel(0, 0,
60, 1));
private JLabel displayField = new JLabel("", SwingConstants.CENTER);
private long startTime;
private long currentTime;
private long deltaTime;
private long setTimeToComplete;
private boolean negative = false;
private Timer timer;
private int hours;
private int min;
private int sec;
private int msec;
private JFrame frame;
public CountDownTimer(JFrame frame) {
this.frame = frame;
displayField.setFont(displayField.getFont().deriveFont(Font.BOLD,
DISPLAY_PTS));
displayField.setBorder(BorderFactory.createLineBorder(Color.blue, 2));
setLayout(new BorderLayout(BL_GAP, BL_GAP));
int eb = 2;
setBorder(BorderFactory.createEmptyBorder(eb, eb, eb, eb));
add(displayField, BorderLayout.NORTH);
add(createGuiBody());
showTimeLeft();
}
private JPanel createGuiBody() {
JPanel bodyPanel = new JPanel();
bodyPanel.setLayout(new BoxLayout(bodyPanel, BoxLayout.PAGE_AXIS));
bodyPanel.add(createSpinnerPanel());
bodyPanel.add(createButtonPanel());
return bodyPanel;
}
private JPanel createButtonPanel() {
JPanel innerBtnPanel = new JPanel(new GridLayout(1, 0, BL_GAP, 0));
for (Action action : btnActions) {
innerBtnPanel.add(new JButton(action));
}
JPanel btnPanel = new JPanel(new BorderLayout());
btnPanel.add(innerBtnPanel);
return btnPanel;
}
private JPanel createSpinnerPanel() {
Font font = hourSpinner.getFont().deriveFont(Font.BOLD, SPINNER_FONT_PTS);
hourSpinner.setFont(font);
minuteSpinner.setFont(font);
secondSpinner.setFont(font);
JPanel spinnerPanel = new JPanel();
spinnerPanel.add(new JLabel("Hrs:"));
spinnerPanel.add(hourSpinner);
spinnerPanel.add(Box.createHorizontalStrut(BL_GAP * 2));
spinnerPanel.add(new JLabel("Min:"));
spinnerPanel.add(minuteSpinner);
spinnerPanel.add(Box.createHorizontalStrut(BL_GAP * 2));
spinnerPanel.add(new JLabel("Secs:"));
spinnerPanel.add(secondSpinner);
return spinnerPanel;
}
private void showTimeLeft() {
int oldMin = min;
hours = (int) (deltaTime / (MS_PER_SEC * SEC_PER_MIN * MIN_PER_HR));
min = (int) (deltaTime / (MS_PER_SEC * SEC_PER_MIN) % MIN_PER_HR);
sec = (int) (deltaTime / (MS_PER_SEC) % SEC_PER_MIN);
msec = (int) (deltaTime % MS_PER_SEC);
String displayString = String.format(DISPLAY_FORMAT_STR, hours, min, sec,
msec / 100);
displayField.setText(displayString);
if (Math.abs(oldMin - min) > 0) {
String title = frame.getTitle().replaceAll("\\d", "");
title = String.format("%02d " + title, min);
frame.setTitle(title);
}
}
private class ResetAction extends AbstractAction {
private StartAction startAction;
public ResetAction(StartAction startAction) {
super("Reset");
putValue(MNEMONIC_KEY, KeyEvent.VK_R);
this.startAction = startAction;
}
public void actionPerformed(ActionEvent evt) {
if (startAction != null
&& startAction.getValue(NAME).equals(StartAction.STOP)) {
startAction.actionPerformed(new ActionEvent(evt.getSource(),
ActionEvent.ACTION_PERFORMED, StartAction.STOP));
} else if (timer != null && timer.isRunning()) {
timer.stop();
}
displayField.setForeground(null);
deltaTime = (Integer) hourSpinner.getValue();
deltaTime = MIN_PER_HR * deltaTime
+ (Integer) minuteSpinner.getValue();
deltaTime = SEC_PER_MIN * deltaTime
+ (Integer) secondSpinner.getValue();
deltaTime = MS_PER_SEC * deltaTime;
showTimeLeft();
negative = false;
timer = new Timer(TIMER_DELAY, new TimerListener());
}
}
private class StartAction extends AbstractAction {
public static final String START = "Start";
public static final String STOP = "Stop";
public StartAction() {
putValue(MNEMONIC_KEY, KeyEvent.VK_S);
putValue(NAME, START);
}
public void actionPerformed(ActionEvent evt) {
if (timer == null) {
return;
}
if (getValue(NAME).equals(START)) {
putValue(NAME, STOP);
startTime = System.currentTimeMillis();
currentTime = startTime;
setTimeToComplete = deltaTime;
timer.start();
} else {
if (timer != null && timer.isRunning()) {
putValue(NAME, START);
timer.stop();
}
}
}
}
private class QuitAction extends AbstractAction {
public QuitAction() {
super("Quit");
putValue(MNEMONIC_KEY, KeyEvent.VK_Q);
}
public void actionPerformed(ActionEvent arg0) {
if (timer != null && timer.isRunning()) {
timer.stop();
}
frame.dispose();
}
}
private class TimerListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent arg0) {
currentTime = System.currentTimeMillis();
deltaTime = setTimeToComplete - currentTime + startTime;
if (deltaTime < 0) {
deltaTime = -deltaTime;
if (!negative) {
negative = true;
displayField.setForeground(NEGATIVE_COLOR);
}
}
showTimeLeft();
}
}
private static void createAndShowGui() {
String title = "Count Down Timer";
title = JOptionPane.showInputDialog("Timer Title?", title);
JFrame frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new CountDownTimer(frame));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}