秒表取消暂停功能无效 [英] Stopwatch unpause doesn't work

查看:120
本文介绍了秒表取消暂停功能无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作秒表。 开始暂停按钮可以正常工作,但取消暂停按钮无法正常工作。
timer 是我的JLabel,我想在其中显示秒表(它引用了JFrame中的 timer )。我无法发布MCVE,因为它的代码太多。

I'm trying to create a stopwatch. The start and pause buttons works fine but the unpause button doesn't work properly. timer is my JLabel in which I want to ilustrate my stopwatch (it references timer from the JFrame). I can't post a MCVE because it's too much code.

这是我的秒表课程:

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

这是我用于按钮的监听器:

This are the listeners I use for my buttons:

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


推荐答案

您需要某种方式来暂停 Thread 并停止进行更新。您可以在 run 循环中使用 if 语句来执行此操作,但是可以通过使用监视锁

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

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

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...

一个更简单的解决方案是只使用Swing Timer

A simpler solution would be to just use a 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));
            }
        }

    }
}

有关更多详细信息,请参见如何使用Swing计时器

See How to use Swing Timers for more details

这篇关于秒表取消暂停功能无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆