通过线程更新GUI

时间:2017-09-14 03:19:36

标签: java multithreading swing thread-synchronization

我对线程很新,并且很长时间没有编写Java,所以请耐心等待。我有一个非常简单的GUI。它有一个计数器,一个状态标签和两个按钮,分别是启动和停止。

我想要它做的是使用counter线程更新我的状态标签。当我点击开始时,它应该在0处开始计数器并且每second递增一次,当我选择点击stop时,它应该suspend当前线程和wait再次按下开始按钮。然而,每当我点击停止它只是暂停等待一秒钟并恢复计数。实际上我希望它保持暂停状态。我不确定为什么要这样做,在发布之前尝试搜索但没有得到任何结果。也可以随意批评你喜欢的任何事情。

以下是我所拥有的:

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

}
}

1 个答案:

答案 0 :(得分:0)

基本上...

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

getStatus正在返回false,因此它正在跳过wait来电(因为t != null

我不确定为什么需要检查这个,但我可能会有enum或其他标志返回更有意义的状态(例如RUNNINGSTOPPED,{{ 1}} ......什么都有)

通过做类似的事情,我能够让它发挥作用。

PAUSED

代替。

尽管如此。我个人会考虑使用Swing synchronized(this) { if(suspended) { wait(); } } 来完成所有这些工作,并在EDT的上下文中触发它的更新

修改原始代码后更新

  

即使你提出了建议的答案,它的行为方式仍然相同,它会暂停一小段时间并立即恢复

您修改了原始帖子中的代码,添加了

Timer

t = new Thread(new CounterThread(this.threadName, this.countLabelName, this.statusLabelName)); 方法,但您的UI代码已经引用了它正在与之交互的start,所以现在您有两个同一个类的实例,一个在后台运行的实例离开,你的UI代码与之交互。

因此,当UI调用CounterThread时,它不会更改实际运行的实例的suspend状态

suspended
  

此外,我不知道在这种情况下使用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; 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(); } } } 是如何运作的

Timer

现在,暂停和恢复问题都得到了解决