2017-09-14 139 views
0

我對線程相當陌生,很長一段時間沒有寫Java,因此請在這裏與我聯繫。我有一個非常簡單的GUI。它有一個計數器,一個狀態標籤和兩個按鈕,分別是開始和停止。通過線程更新圖形用戶界面

我想要做的是使用counter線程更新我的狀態標籤。當我點擊開始時,它應該在0處啓動計數器,並且每增加一個second,當我選擇點擊stop時,它應該suspend當前線程和wait爲開始按鈕再次按下。然而,無論何時我停下來,它都會暫停等待一秒鐘,然後重新開始計數。實際上,我希望它保持暫停狀態。我不確定爲什麼會這樣做,在發佈之前嘗試搜索它,但什麼都沒有。也可以隨意批評任何你想要的東西。

這是我有:

更新,如PER @ MadProgrammer的答案。

import java.awt.Font; 
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 static javax.swing.JFrame.EXIT_ON_CLOSE; 
import javax.swing.JLabel; 
import javax.swing.SwingUtilities; 

public class main extends JFrame 
{ 


    JLabel countLabel = new JLabel("0"); 
    JLabel statusLabel = new JLabel("Task not completed."); 
    JButton startButton = new JButton("Start"); 
    JButton stopButton = new JButton("Stop"); 
    CounterThread worker = new CounterThread("worker", countLabel, statusLabel); 

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

      @Override 
      public void run() { 
       new Main("Counter Demo"); 
      } 
     }); 
    } 

    public Main(String title) { 
     super(title); 

     setLayout(new GridBagLayout()); 

     countLabel.setFont(new Font("serif", Font.BOLD, 28)); 

     GridBagConstraints gc = new GridBagConstraints(); 

     gc.fill = GridBagConstraints.NONE; 

     gc.gridx = 0; 
     gc.gridy = 0; 
     gc.weightx = 1; 
     gc.weighty = 1; 
     add(countLabel, gc); 

     gc.gridx = 0; 
     gc.gridy = 1; 
     gc.weightx = 1; 
     gc.weighty = 1; 
     add(statusLabel, gc); 

     gc.gridx = 0; 
     gc.gridy = 2; 
     gc.weightx = 1; 
     gc.weighty = 1; 
     add(startButton, gc); 

     gc.gridx = 0; 
     gc.gridy = 3; 
     gc.weightx = 1; 
     gc.weighty = 1; 
     add(stopButton, gc); 

     startButton.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent arg0) { 
       worker.start(); 
       //notify(); 
      } 
     }); 
     stopButton.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent arg0) { 
       worker.suspend(); 
      } 
     }); 
     setSize(200, 400); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     setVisible(true); 
    } 

public class CounterThread implements Runnable { 

    public Thread t; 
    public String threadName; 
    boolean suspended = false; 
    JLabel countLabelName; 
    JLabel statusLabelName; 

    CounterThread(String name, JLabel cLabel, JLabel sLabel) { 
     this.threadName = name; 
     this.countLabelName = cLabel; 
     this.statusLabelName = sLabel; 
    } 

    public void run() { 
     try { 
      // Simulate doing something useful. 
      for (int i = 0; i <= 10; i++) { 
       synchronized (this) { 
        if (suspended) 
        {    
         wait(); 
        } 
       } 
       final int count = i; 

       SwingUtilities.invokeLater(new Runnable() { 
        public void run() { 
         countLabelName.setText(Integer.toString(count)); 
        } 
       }); 
       Thread.sleep(1000); 
      } 
     } catch (InterruptedException e) { 
     } 

     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       statusLabelName.setText("Completed."); 
      } 
     }); 

     this.start(); 
    } 

    public boolean getStatus() { 
     return t == null; 
    } 

    public void start() { 
     if (getStatus()) { 
      //t = new Thread(new CounterThread(this.threadName, this.countLabelName, this.statusLabelName)); 
      t = new Thread(this); 
      t.start(); 
     } 
    } 

    public void suspend() { 
     statusLabelName.setText("Task is paused"); 
     suspended = true; 
    } 
    //create an object whose only purpose is to synchronize 

    synchronized void resume() { 
     statusLabelName.setText("Task has resumed"); 
     suspended = false; 
     this.notify(); 
    } 

} 
} 
+0

最好的辦法是審查甲骨文的Swing和線程教程,並檢查了相關擺動實用工具類,其中一些要導入但從不使用。同樣,你似乎知道java.util.concurrent,但沒有使用它。避免直接使用同步原語,'notify'等。清理你的代碼及其縮進,並且 - 你有一個實現了runnable但包含一個線程的類,並啓動一個線程,很難跟蹤正在發生的事情,可能是因爲你也是。 – pvg

+0

除非你有特別需要做一些額外的處理的背景下,我會考慮在使用Swing的在看看'Timer'代替 – MadProgrammer

+0

'布爾暫停= FALSE;'或許也會被標記'volatile'(或使用一個'AtomicBoolean') – MadProgrammer

回答

0

基本上...

synchronized(this) 
{ 
    if(suspended) 
    { 
     if(getStatus()) 
      wait(); 
     resume(); 
    } 
} 

getStatus將返回false所以它跳過wait調用(因爲t != null

我真的不知道爲什麼需要檢查,但我可能有enum或返回更有意義的狀態的其他標誌(如RUNNING,STOPPED,PAUSED ...什麼)

我能夠讓它做類似工作...

synchronized(this) 
{ 
    if(suspended) 
    { 
     wait(); 
    } 
} 

代替。

儘管如此。我個人認爲使用Swing的Timer它會做這一切爲你工作,並會觸發它的EDT

原代碼後更新修改

即使您建議的回答它的範圍內更新仍然表現以同樣的方式,它掛起它短短的一秒鐘,重新開始的時候了

您修改從原來的職位代碼,添加

t = new Thread(new CounterThread(this.threadName, this.countLabelName, this.statusLabelName)); 

start方法,但你的UI代碼已經具備了CounterThread一個參考,它與互動,所以現在你有相同的類,其中一個是在後臺運行的滴答作響的兩個實例,一個,你的UI代碼與...交互。

所以當UI調用suspend,它不改變實例的suspended狀態,這實際上是運行

import java.awt.Font; 
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 static javax.swing.JFrame.EXIT_ON_CLOSE; 
import javax.swing.JLabel; 
import javax.swing.SwingUtilities; 

public class Main extends JFrame { 

    JLabel countLabel = new JLabel("0"); 
    JLabel statusLabel = new JLabel("Task not completed."); 
    JButton startButton = new JButton("Start"); 
    JButton stopButton = new JButton("Stop"); 
    int holder; 
    CounterThread worker = new CounterThread("worker", countLabel, statusLabel); 

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

      @Override 
      public void run() { 
       new Main("Counter Demo"); 
      } 
     }); 
    } 

    public Main(String title) { 
     super(title); 

     setLayout(new GridBagLayout()); 

     countLabel.setFont(new Font("serif", Font.BOLD, 28)); 

     GridBagConstraints gc = new GridBagConstraints(); 

     gc.fill = GridBagConstraints.NONE; 

     gc.gridx = 0; 
     gc.gridy = 0; 
     gc.weightx = 1; 
     gc.weighty = 1; 
     add(countLabel, gc); 

     gc.gridx = 0; 
     gc.gridy = 1; 
     gc.weightx = 1; 
     gc.weighty = 1; 
     add(statusLabel, gc); 

     gc.gridx = 0; 
     gc.gridy = 2; 
     gc.weightx = 1; 
     gc.weighty = 1; 
     add(startButton, gc); 

     gc.gridx = 0; 
     gc.gridy = 3; 
     gc.weightx = 1; 
     gc.weighty = 1; 
     add(stopButton, gc); 

     startButton.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent arg0) { 
       worker.start(); 
      } 

     }); 

     stopButton.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent arg0) { 
       worker.suspend(); 
      } 
     }); 
     setSize(200, 400); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     setVisible(true); 
    } 

    public class CounterThread implements Runnable { 

     public Thread t; 
     public String threadName; 
     boolean suspended = false; 
     JLabel countLabelName; 
     JLabel statusLabelName; 

     CounterThread(String name, JLabel cLabel, JLabel sLabel) { 
      this.threadName = name; 
      this.countLabelName = cLabel; 
      this.statusLabelName = sLabel; 
     } 

     public void run() { 
      try { 
       // Simulate doing something useful. 
       for (int i = 0; i <= 10; i++) { 
        synchronized (this) { 
         if (suspended) { 
          wait(); 
         } 
        } 
        final int count = i; 

        SwingUtilities.invokeLater(new Runnable() { 
         public void run() { 
          countLabelName.setText(Integer.toString(count)); 
         } 
        }); 

        Thread.sleep(1000); 

       } 
      } catch (InterruptedException e) { 
      } 

      SwingUtilities.invokeLater(new Runnable() { 
       public void run() { 
        statusLabelName.setText("Completed."); 
       } 
      }); 

      this.start(); 
     } 

     public boolean getStatus() { 
      return t == null; 
     } 

     public void start() { 
      if (getStatus()) { 
       //t = new Thread(new CounterThread(this.threadName, this.countLabelName, this.statusLabelName)); 
       t = new Thread(this); 
       t.start(); 
      } 
     } 

     public void suspend() { 
      statusLabelName.setText("Task is paused"); 
      suspended = true; 
     } 
     //create an object whose only purpose is to synchronize 

     synchronized void resume() { 
      statusLabelName.setText("Task has resumed"); 
      suspended = false; 
      this.notify(); 
     } 

    } 
} 

另外,我不明白如何使用Swing的計時器會幫我在這情況下,由於有在等待沒有實際延遲

那你顯然不明白Timer如何工作

import java.awt.Font; 
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 static javax.swing.JFrame.EXIT_ON_CLOSE; 
import javax.swing.JLabel; 
import javax.swing.SwingUtilities; 
import javax.swing.Timer; 

public class Main extends JFrame { 

    JLabel countLabel = new JLabel("0"); 
    JLabel statusLabel = new JLabel("Task not completed."); 
    JButton startButton = new JButton("Start"); 
    JButton stopButton = new JButton("Stop"); 
    int holder; 

    Timer timer; 
    int count = 0; 

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

      @Override 
      public void run() { 
       new Main("Counter Demo"); 
      } 
     }); 
    } 

    public Main(String title) { 
     super(title); 

     setLayout(new GridBagLayout()); 

     countLabel.setFont(new Font("serif", Font.BOLD, 28)); 

     GridBagConstraints gc = new GridBagConstraints(); 

     gc.fill = GridBagConstraints.NONE; 

     gc.gridx = 0; 
     gc.gridy = 0; 
     gc.weightx = 1; 
     gc.weighty = 1; 
     add(countLabel, gc); 

     gc.gridx = 0; 
     gc.gridy = 1; 
     gc.weightx = 1; 
     gc.weighty = 1; 
     add(statusLabel, gc); 

     gc.gridx = 0; 
     gc.gridy = 2; 
     gc.weightx = 1; 
     gc.weighty = 1; 
     add(startButton, gc); 

     gc.gridx = 0; 
     gc.gridy = 3; 
     gc.weightx = 1; 
     gc.weighty = 1; 
     add(stopButton, gc); 

     timer = new Timer(1000, new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       count++; 
       countLabel.setText(Integer.toString(count)); 
      } 
     }); 

     startButton.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent arg0) { 
       timer.start(); 
      } 

     }); 

     stopButton.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent arg0) { 
       if (timer.isRunning()) { 
        timer.stop(); 
        stopButton.setText("Resume"); 
       } else { 
        timer.restart(); 
        stopButton.setText("Stop"); 
       } 
      } 
     }); 
     setSize(200, 400); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     setVisible(true); 

    } 
} 

現在,有暫停和恢復問題的所有照顧過

+0

我明白了,我的印象是'return t == null'返回我線程的狀態,即RUNNING,STOPPED。即使您的建議答案仍然是相同的方式,它會立即暫停並立即恢復 –

+0

您已更改原始帖子中的代碼。在'start'方法中,您正在執行't = new Thread(new CounterThread(this.threadName,this.countLabelName,this.statusLabelName));',但是您的UI代碼正在與另一個實例進行交互 - 'CounterThread worker =新的反螺紋(「工人」,countLabel,statusLabel);' - 有沒有辦法,你現在可以修改這實際上是運行的線程的代碼(我改了名字) – MadProgrammer

+0

至少它保持現在暫停,我只需要弄清楚一旦再次按下開始按鈕,如何正確使用'notify'來恢復計數器。另外,我沒有看到在這種情況下如何使用Swing Timer來幫助我,因爲等待沒有實際的延遲。我只是在等待,直到啓動按鈕再次 –