Java - 更新现有的秒表代码以包括倒计时

时间:2015-11-04 02:06:31

标签: java swing timer countdown

@HovercraftFullofEels非常友好地通过为我提供以下代码的基础来帮助我,我对其进行了一些修改(标记为“行完全添加”注释和最后的巨大注释,其中包含要放置的代码在文件的某个地方)。

原始文件是一个简单的秒表,我的修改包括3个JTextFields.that接收分钟,秒和CENTI秒(1厘秒= 1/100秒)。我想要包含一个“提交”按钮,它允许程序读取这3个文本字段的输入。我编写了单击“提交”时要调用的方法的代码(包含在最后的巨型注释中)。单击它后,我希望程序立即从秒表开始的值开始倒计时,而不是从单击按钮开始倒计时。例如,如果秒表在用户点击“提交”并且输入时间为25分钟时已经运行了20分钟,则将开始5分钟的倒计时。

如果这仍然令人困惑,那么你真正需要知道的是我的方法以一条线结束,该线提供了我希望倒计时开始的毫秒表示,此时我想要倒计时来替换秒表。我还想删除“暂停”和“停止”按钮,但不是“开始”按钮(你会认为它们很容易删除,但我删除了我认为合适并在编译时收到错误)并替换他们使用单个“提交”按钮。

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.Font;                     //line completely added
import javax.swing.*;

@SuppressWarnings("serial")
public class MyTimer2 extends JPanel implements GuiTimer {
    private static final String TIME_FORMAT = "%02d:%02d:%02d";   //changed from "%03d:%03d"
    private static final int EXTRA_WIDTH = 50;
    private JLabel timerLabel = new JLabel();
    private TimerControl timerControl = new TimerControl(this);

    JTextField minsField, secsField, centisField;     //line completely added - should this be private?
    JLabel colon, period;                             //line completely added - should this be private?

    public MyTimer2() {
        JPanel topPanel = new JPanel();
        topPanel.add(timerLabel);

        timerLabel.setFont(new Font("Arial", Font.BOLD, 64));     //line completely added

        minsField = new JTextField("", 2);
        secsField = new JTextField("", 2);
        centisField = new JTextField("", 2);

        colon = new JLabel(":");
        period = new JLabel(".");

        JPanel centerPanel = new JPanel();
        centerPanel.add(minsField);          //line completely added
        centerPanel.add(colon);              //line completely added
        centerPanel.add(secsField);          //line completely added
        centerPanel.add(period);             //line completely added
        centerPanel.add(centisField);        //line completely added

        JPanel bottomPanel = new JPanel();                              //line completely added
        bottomPanel.add(new JButton(timerControl.getStartAction()));    //changed from centerPanel
        bottomPanel.add(new JButton(timerControl.getStopAction()));     //changed from centerPanel

        setLayout(new BorderLayout());
        add(topPanel, BorderLayout.PAGE_START);
        add(centerPanel, BorderLayout.CENTER);
        add(bottomPanel, BorderLayout.PAGE_END);   //line completely added

        setDeltaTime(0);
    }

    @Override
    public void setDeltaTime(int delta) {
        int mins = (int) delta / 60000;                                          // line completely added
        int secs = ((int) delta % 60000) / 1000;                                 // %60000 added
        int centis = ((int) delta % 1000) / 10;                                  // / 10 added
        timerLabel.setText(String.format(TIME_FORMAT, mins, secs, centis));      // mins added; mSecs changed to centis
    }

    @Override
    public Dimension getPreferredSize() {
        Dimension superSz = super.getPreferredSize();
        if (isPreferredSizeSet()) {
            return superSz;
        }
        int prefW = superSz.width + EXTRA_WIDTH;
        int prefH = superSz.height;
        return new Dimension(prefW, prefH);
    }

    private static void createAndShowGui() {
        MyTimer2 mainPanel = new MyTimer2();

        JFrame frame = new JFrame("MyTimer2");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  //changed from DISPOSE_ON_CLOSE
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui();
            }
        });
    }
}

interface GuiTimer {
    public abstract void setDeltaTime(int delta);
}

@SuppressWarnings("serial")
class TimerControl {
    private static final int TIMER_DELAY = 10;
    private long startTime = 0;
    private long pauseTime = 0;
    private Timer timer;
    private GuiTimer gui;
    private StartAction startAction = new StartAction();
    private StopAction stopAction = new StopAction();

    public TimerControl(GuiTimer gui) {
        this.gui = gui;
    }

    public Action getStopAction() {
        return stopAction;
    }

    public Action getStartAction() {
        return startAction;
    }

    enum State {
        START("Start", KeyEvent.VK_S), 
        PAUSE("Pause", KeyEvent.VK_P);
        private String text;
        private int mnemonic;

        private State(String text, int mnemonic) {
            this.text = text;
            this.mnemonic = mnemonic;
        }

        public String getText() {
            return text;
        }

        public int getMnemonic() {
            return mnemonic;
        }
    };

    private class StartAction extends AbstractAction {
        private State state;

        public StartAction() {
            setState(State.START);
        }

        public final void setState(State state) {
            this.state = state;
            putValue(NAME, state.getText());
            putValue(MNEMONIC_KEY, state.getMnemonic());
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (state == State.START) {
                if (timer != null && timer.isRunning()) {
                    return; // the timer's already running
                }
                setState(State.PAUSE);
                if (startTime <= 0) {
                    startTime = System.currentTimeMillis();
                    timer = new Timer(TIMER_DELAY, new TimerListener());
                } else {
                    startTime += System.currentTimeMillis() - pauseTime;
                }
                timer.start();
            } else if (state == State.PAUSE) {
                setState(State.START);
                pauseTime = System.currentTimeMillis();
                timer.stop();
            }
        }
    }

    private class StopAction extends AbstractAction {
        public StopAction() {
            super("Stop");
            int mnemonic = KeyEvent.VK_T;
            putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (timer == null) {
                return;
            }
            timer.stop();
            startAction.setState(State.START);
            startTime = 0;
        }
    }

    private class TimerListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            long time = System.currentTimeMillis();
            long delta = time - startTime;
            gui.setDeltaTime((int) delta); 
        }
    }

}

/*not sure where this will go, but this is the code for clicking "Submit"   

   //upon clicking "Submit"...
   public void actionPerformed(ActionEvent e)
   {      
      String minsStr = minsField.getText();
      String secsStr = secsField.getText();
      String centisStr = centisField.getText();
      int minsInput = Integer.parseInt(minsStr);
      int secsInput = Integer.parseInt(secsStr);
      int centisInput = Integer.parseInt(centisStr);

      long millis = minsInput * 60000 + secsInput * 1000 + centisInput * 10;

      long millisCountdown = millis - delta;   //where "delta" is elapsed milliseconds

      if(millisCountdown < 0)
          JOptionPane.showMessageDialog("Invalid time entered.");

      else
          //then immediately change from stopwatch to countdown beginning from millisCountdown and ending at 00:00:00

      minsField.setText("");     //clear minsField
      secsField.setText("");     //clear secsField
      centisField.setText("");   //clear centisField
   }
*/

如果有人能帮助我,我会非常感激。不幸的是,我不了解Hovercraft的大部分代码,所以我不知道我已经完成了什么。

谢谢!

编辑:这是@ MadProgrammer代码的更新版本:

import java.awt.EventQueue;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Font;
import java.time.Duration;
import java.time.LocalTime;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class StopWatch {

    public static void main(String[] args) {
        new StopWatch();
    }

    public StopWatch() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class TestPane extends JPanel {

        protected static final String TIME_FORMAT = "%02d:%02d.%02d";

        private LocalTime startTime;
        private LocalTime targetTime;

        private JLabel label;
        private JTextField minsField, secsField, centisField;
        private JButton start, submit;

        private Timer timer;

        public TestPane() {
            JPanel topRow = new JPanel();
            JPanel centerRow = new JPanel();
            JPanel bottomRow = new JPanel();

            label = new JLabel(formatDuration(Duration.ofMillis(0)));
            topRow.add(label);

            minsField = new JTextField("", 2);
            secsField = new JTextField("", 2);
            centisField = new JTextField("", 2);
            centerRow.add(minsField);
            centerRow.add(secsField);
            centerRow.add(centisField);

            start = new JButton("Start");
            start.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (!timer.isRunning()) {
                        startTime = LocalTime.now();
                        timer.start();
                    }
                }
            });

            bottomRow.add(start);

            submit = new JButton("Submit");
            submit.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                if (timer.isRunning()) {
                        timer.stop();

                        Duration runningTime = Duration.between(startTime, LocalTime.now());
                        // Subtract the required amount of time from the duration

                        String minsStr = minsField.getText();
                        String secsStr = secsField.getText();
                        String centisStr = centisField.getText();

                        if(minsStr.matches("\\d+$") && secsStr.matches("\\d+$") && centisStr.matches("\\d+$"))
                        {                       
                           int minsInput = Integer.parseInt(minsStr);
                           int secsInput = Integer.parseInt(secsStr);
                           int centisInput = Integer.parseInt(centisStr);

                           if(minsInput >= 0 && secsInput >= 0 && secsInput < 60 && centisInput >= 0 && centisInput < 100)
                           {

                              long millis = minsInput * 60000 + secsInput * 1000 + centisInput * 10;

                              runningTime = runningTime.minusMillis(millis);

                              timer.start();

                              // No negative times
                              if (runningTime.toMillis() > 0)
                              {
                                  // When the timer is to end...
                                  targetTime = LocalTime.now().plus(runningTime);
                              }

                              else
                              {
                                 JOptionPane.showMessageDialog(null, "Invalid time entered.");
                              }
                           }

                           else
                           {
                              timer.start();
                              JOptionPane.showMessageDialog(null, "Invalid time entered.");
                           }
                        }

                        else
                        {
                           timer.start();
                           JOptionPane.showMessageDialog(null, "Invalid time entered.");
                        }

                        minsField.setText("");
                        secsField.setText("");
                        centisField.setText("");
                    }
                }
            });

            bottomRow.add(submit);

            timer = new Timer(10, new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    if (targetTime != null) {
                        Duration duration = Duration.between(LocalTime.now(), targetTime);
                        if (duration.toMillis() <= 0) {
                            duration = Duration.ofMillis(0);
                            timer.stop();
                            targetTime = null;
                        }
                        label.setText(formatDuration(duration));
                    } else {
                        // Count up...
                        Duration duration = Duration.between(startTime, LocalTime.now());
                        label.setText(formatDuration(duration));
                    }
                }
            });

            setLayout(new BorderLayout());

            label.setFont(new Font("Arial", Font.BOLD, 64));

            add(topRow, BorderLayout.PAGE_START);
            add(centerRow, BorderLayout.CENTER);
            add(bottomRow, BorderLayout.PAGE_END);
        }

        protected String formatDuration(Duration duration) {
            long mins = duration.toMinutes();
            duration = duration.minusMinutes(mins);
            long seconds = duration.toMillis() / 1000;
            duration = duration.minusSeconds(seconds);
            long centis = duration.toMillis() / 10;

            return String.format(TIME_FORMAT, mins, seconds, centis);
        }
    }
}

1 个答案:

答案 0 :(得分:2)

这使用新的Java 8 Time API来简化过程,允许您计算两个时间点之间的持续时间以及算术

请参阅Date and Time Classes

enter image description here

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.LocalTime;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class StopWatch {

    public static void main(String[] args) {
        new StopWatch();
    }

    public StopWatch() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class TestPane extends JPanel {

        protected static final String TIME_FORMAT = "%02dh %02dm %02ds";

        private LocalTime startTime;
        private LocalTime targetTime;

        private JLabel label;
        private JButton start;

        private Timer timer;

        public TestPane() {
            label = new JLabel(formatDuration(Duration.ofMillis(0)));

            start = new JButton("Start");
            start.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (timer.isRunning()) {
                        timer.stop();

                        Duration runningTime = Duration.between(startTime, LocalTime.now());
                        // Subtract the required amount of time from the duration
                        runningTime = runningTime.minusSeconds(5);

                        // No negative times
                        if (runningTime.toMillis() > 0) {
                            // When the timer is to end...
                            targetTime = LocalTime.now().plus(runningTime);
                            timer.start();
                        }
                    } else {
                        startTime = LocalTime.now();
                        timer.start();
                    }
                }
            });

            timer = new Timer(500, new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    if (targetTime != null) {
                        Duration duration = Duration.between(LocalTime.now(), targetTime);
                        if (duration.toMillis() <= 0) {
                            duration = Duration.ofMillis(0);
                            timer.stop();
                            targetTime = null;
                        }
                        label.setText(formatDuration(duration));
                    } else {
                        // Count up...
                        Duration duration = Duration.between(startTime, LocalTime.now());
                        label.setText(formatDuration(duration));
                    }
                }
            });

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;

            add(label, gbc);
            add(start, gbc);

        }

        protected String formatDuration(Duration duration) {
            long hours = duration.toHours();
            duration = duration.minusHours(hours);
            long mins = duration.toMinutes();
            duration = duration.minusMinutes(mins);
            long seconds = duration.toMillis() / 1000;

            return String.format(TIME_FORMAT, hours, mins, seconds);
        }

    }

}
  

我还想删除&#34;暂停&#34;和&#34;停止&#34;按钮(你会认为它们很容易删除,但我删除了我认为合适并在编译时收到错误)并将其替换为单个&#34;提交&#34;按钮。

请查看Creating a GUI With JFC/Swing了解详情

  

不幸的是,我不了解Hovercraft的大部分代码

我们为您提供的任何其他解决方案都将获得相同的结果。您需要将需求分解为可管理的块,计算定时器如何向前移动,然后确定如何使其向后移动,然后找出如何组合这两个概念,以便从运行中减去目标值时间并向后移动。