Stopwatch unpause doesn't work

前端 未结 1 1787
攒了一身酷
攒了一身酷 2021-01-28 16:52

I\'m trying to create a stopwatch. The start and pause buttons works fine but the unpause button doesn\'t work properly.

1条回答
  •  日久生厌
    2021-01-28 17:26

    You need someway to pause the Thread and stop the update from occurring. You could do this with an if statement inside your run loop, but there is a more efficient way through the use of monitor lock

    public class Stopwatch extends Thread {
        //...
        private final Object pauseLock;
    
        public Stopwatch() {
            pauseLock = new Object();
        }
    
        public Stopwatch(boolean finished, boolean pause, boolean sort, JLabel timer) {
            this();
            //...
        }
    
        @Override
        public void run() {
            long startTime = System.currentTimeMillis();
            while (sortFlag && !finishedFlag) {
                while (pauseFlag) {
                    synchronized (pauseLock) {
                        try {
                            pauseLock.wait();
                        } catch (InterruptedException ex) {
                        }
                    }
                }
                update(summedTime + (System.currentTimeMillis() - startTime));
            }
            if (pauseFlag) {
                summedTime += System.currentTimeMillis() - startTime;
            } else {
                summedTime = 0;
            }
        }
    

    Now, you need some way to pause and resume the run loop

    public void setPaused(boolean paused) {
        if (paused && !pauseFlag) {
            pauseFlag = paused;
        } else if (!paused && pauseFlag) {
            pauseFlag = paused;
            synchronized (pauseLock) {
                pauseLock.notifyAll();
            }
        }
    }
    

    Now, however, we have bigger problem, Swing is NOT thread safe. This means that your update method is breaking the single thread rules of Swing and could cause no end of issues...

    A simpler solution would be to just use a Swing Timer

    Swing Timer

    import java.awt.EventQueue;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    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 Test {
    
        public static void main(String[] args) {
            new Test();
        }
    
        public Test() {
            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 class TestPane extends JPanel {
    
            private JLabel label;
            private StopWatch sw;
    
            public TestPane() {
    
                setLayout(new GridBagLayout());
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridwidth = GridBagConstraints.REMAINDER;
    
                label = new JLabel("...");
                add(label, gbc);
    
                sw = new StopWatch(label);
    
                JButton btn = new JButton("Resume");
                btn.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        sw.setPaused(!sw.isPaused());
                        btn.setText(sw.isPaused() ? "Resume" : "Pause");
                    }
                });
                add(btn, gbc);
            }
    
        }
    
        public class StopWatch {
    
            private Timer timer;
            private JLabel label;
    
            private int runningTime;
            private long tickTime;
    
            public StopWatch(JLabel label) {
                this.label = label;
                timer = new Timer(10, new ActionListener() {
    
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        runningTime += (System.currentTimeMillis() - tickTime);
                        System.out.println(runningTime);
                        update(runningTime);
                        tickTime = System.currentTimeMillis();
                    }
                });
            }
    
            public void setPaused(boolean paused) {
                if (paused && timer.isRunning()) {
                    timer.stop();
                } else if (!paused && !timer.isRunning()) {
                    tickTime = System.currentTimeMillis();
                    timer.start();
                }
            }
    
            public boolean isPaused()  {
                return !timer.isRunning();
            }
    
            private void update(long dT) {
                long x = (dT / 1000) % 60;
                long y = (dT / 60000) % 1000;
                if (x >= 0 && x <= 9 && y >= 0 && y <= 9) {
                    label.setText("0" + String.valueOf((dT / 60000) % 1000) + ":0" + String.valueOf((dT / 1000) % 60) + "," + String.valueOf((dT) % 1000));
                } else if (x > 9 && y >= 0 && y <= 9) {
                    label.setText("0" + String.valueOf((dT / 60000) % 1000) + ":" + String.valueOf((dT / 1000) % 60) + "," + String.valueOf((dT) % 1000));
                } else if (x >= 0 && x <= 9 && y > 9) {
                    label.setText(String.valueOf((dT / 60000) % 1000) + ":0" + String.valueOf((dT / 1000) % 60) + "," + String.valueOf((dT) % 1000));
                } else if (x > 9 && y > 9) {
                    label.setText(String.valueOf((dT / 60000) % 1000) + ":" + String.valueOf((dT / 1000) % 60) + "," + String.valueOf((dT) % 1000));
                }
            }
    
        }
    }
    

    See How to use Swing Timers for more details

    0 讨论(0)
提交回复
热议问题