2017-09-14 141 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来帮助我,因为等待没有实际的延迟。我只是在等待,直到启动按钮再次 –