美好的一天,
我已经阅读了其他一些堆栈溢出帖子和其他教程,但是在按钮启动一个很长的过程后,我无法让我的GUI正确更新。我附上了我遇到的问题的完整代码。请注意,如果运行代码,JList会在结束时立即更新,而不是for循环的每次迭代。
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();
}
}
}
}
}
非常感谢任何帮助。
答案 0 :(得分:4)
将在Event Dispatch Thread上调用actionPerformed
方法。在EDT上调用Thread.sleep
会阻止它更新GUI。由于您的GUI无法更新,因此在您的循环退出之前,JList
在添加项目时不会自行重新绘制。
您应该使用SwingWorker
。 (SwingWorker
tutorial.)
答案 1 :(得分:4)
您的问题是您已经从EDT(事件调度线程)调用invokeLater
方法。
从EDT调用方法actionPerformed
,所以会发生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();
}