2015-04-13 94 views
0

我正在嘗試創建秒錶。 開始暫停按鈕工作正常,但取消暫停按鈕無法正常工作。 定時器是我的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); 
+0

您需要在您的主循環中放置一個監視器鎖 – MadProgrammer

+0

您是指在run()方法的while循環中?單擊暫停按鈕時將其鎖定並在單擊取消暫停按鈕時將其解鎖? – Andrew

回答

3

你需要某種方式暫停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 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