秒表取消暂停不起作用

时间:2015-04-13 00:34:03

标签: java swing timer actionlistener

我试图制作一个秒表。 开始暂停按钮工作正常但取消暂停按钮无法正常工作。 计时器是我的JLabel,其中我想说明我的秒表(它从JFrame引用计时器)。我无法发布MCVE,因为它的代码太多了。

这是我的秒表类:

public class Stopwatch extends Thread {

    private boolean finishedFlag = false;
    private boolean pauseFlag = false;
    private boolean sortFlag = false;
    private long summedTime = 0;
    private JLabel timer;

    public Stopwatch(){}

    public Stopwatch(boolean finished, boolean pause, boolean sort, JLabel timer){
        this.finishedFlag = finished;
        this.pauseFlag = pause;
        this.sortFlag = sort;
        this.timer = timer;
    }

    @Override
    public void run() {
        long startTime = System.currentTimeMillis();
        while(sortFlag && !pauseFlag && !finishedFlag) {
            update(summedTime + (System.currentTimeMillis() - startTime));
        }
        if(pauseFlag)
            summedTime += System.currentTimeMillis() - startTime;
        else 
            summedTime = 0;
    }

    private void update(long dT){
        long x = (dT/1000)%60;
        long y = (dT/60000)%1000;
        if(x>=0 && x<=9 && y>=0 && y<=9)
            timer.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)
            timer.setText("0"+String.valueOf((dT/60000)%1000)+":"+String.valueOf((dT/1000)%60)+","+String.valueOf((dT)%1000));
        else if(x>=0 && x<=9 && y>9)
            timer.setText(String.valueOf((dT/60000)%1000)+":0"+String.valueOf((dT/1000)%60)+","+String.valueOf((dT)%1000));
        else if(x>9 && y>9)
            timer.setText(String.valueOf((dT/60000)%1000)+":"+String.valueOf((dT/1000)%60)+","+String.valueOf((dT)%1000));
    }
}

这是我用于按钮的听众:

ActionListener sortListener = new ActionListener(){

        @Override
        public void actionPerformed(ActionEvent e) {
            if(sortFlag == false && pauseFlag == false)
            {
                sortFlag = true;
                System.out.println("sort");
                stopwatch1 = new Stopwatch(finishedFlag,pauseFlag,sortFlag,timer1);
                stopwatch1.start();
                appFrame.validate();
                appFrame.repaint();
            }
        }
    };
    sortButton.addActionListener(sortListener);

    ActionListener pauseListener = new ActionListener(){

        @Override
        public void actionPerformed(ActionEvent e) {
            if(sortFlag && pauseFlag == false)
            {
                pauseFlag = true;
                timeSpent = stopwatch1.getSummedTime();
                stopwatch1.setPauseFlag(true);
                System.out.println("pause");
            }
        }
    };
    pauseButton.addActionListener(pauseListener);

    ActionListener unpauseListener = new ActionListener(){

        @Override
        public void actionPerformed(ActionEvent e) {
            if(sortFlag && pauseFlag)
            {
                pauseFlag = false;
                stopwatch1.setPauseFlag(false);
                stopwatch1.run();
                System.out.println("unpause");
            }
        }
    };
    unpauseButton.addActionListener(unpauseListener);

1 个答案:

答案 0 :(得分:2)

您需要暂停Thread并停止更新。您可以在if循环内使用run语句执行此操作,但使用监视锁定有一种更有效的方法

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;
        }
    }

现在,您需要一些方法来暂停和恢复run循环

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

但是,现在我们遇到了更大的问题,Swing不是线程安全的。这意味着您的update方法违反了Swing的单线程规则,并且可能导致问题无法结束......

更简单的解决方案是使用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));
            }
        }

    }
}

有关详细信息,请参阅How to use Swing Timers