SwingUtilities invokeLater方式更新JList的GUI

3

您好,

我已经阅读了一些其他的stackoverflow文章和教程,但是在按钮启动长时间进程后,我无法正确更新我的GUI。我附上了我所遇到问题的完整代码。请注意,如果您运行代码,JList会在最后一次迭代时全部更新,而不是每次迭代。

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class theframe extends JFrame implements ActionListener
{
    private JList list;
    private DefaultListModel listmodel;
    private JButton start;

    public theframe()
    {
        listmodel = new DefaultListModel();
        list = new JList(listmodel);
        start = new JButton("Start");

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(500,500);
        setVisible(true);

        list.setPreferredSize(new Dimension(200,200));

        start.addActionListener(this);
        JPanel p = new JPanel();
        p.add(start);
        p.add(list);

        this.add(p);
    }

    public static void main(String[] args)
    {
        theframe frame = new theframe();

    }

    @Override
    public void actionPerformed(ActionEvent arg0)
    {
        if(arg0.getSource() == start)
        {
            for(int i=0;i<10;i++)
            {   
                SwingUtilities.invokeLater(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        // the JList should update one by one
                        listmodel.addElement("Start pushed ");
                    }
                });



                try
                {
                                    //This thread sleep simulates a long job
                    Thread.sleep(300);
                } 
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
}

任何帮助都将不胜感激。
2个回答

4
actionPerformed方法将在事件分派线程上调用。在EDT上调用Thread.sleep会停止GUI的更新。由于您的GUI无法更新,因此只有在循环退出后,您的JList才会在向其中添加项目时自动重绘。
您应该使用SwingWorker。(SwingWorker教程。

4
您遇到的问题是您已经在EDT(事件分发线程)中调用了invokeLater方法。 actionPerformed方法是从EDT中调用的,因此sleep调用只会停止EDT本身。您可以想象这不是它应该工作的方式,没有运行的EDT意味着没有GUI更新。
由于这是一个耗时的任务,您应该将其实现为一个Thread/Runnable,以便可以并行执行,然后从另一个线程调用invokeLater
类似于以下内容:
class LongProcess extends Thread {
  public void run() {
    for (int i = 0; i < 10; ++i) {
      SwingUtilities.invokeLater(...);
      Thread.sleep(300);
    }
  }
}

void actionPerformed(ActionEvent e) {
  LongProcess process = new LongProcess();
  process.start();
}

当我正在输入答案时,Jack已经回答了。所以我会+1他的答案,因为这正是我想说的 :) 另外需要注意的是,在线程中更新Swing/AWT组件应该使用SwingUtilities.invokeLater() - george_h
谢谢@Jack和george_h!非常感谢!我之前不明白actionPerformed是来自EDT的,但现在我想我明白了。感谢您的快速回复! - Matthew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接