我是Swing的新手,我试图这样做:
在按下JButton时,程序将开始迭代数百个项目,每个项目处理1秒钟,在完成每个项目后,他应该更新标签以显示已处理的项目数。
问题是,在循环完成所有项目的迭代之前,标签的文本不会更新。
我在网上搜索,显然是因为它在同一个线程中运行,所以我创建了一个新线程来处理数据并更新要在标签中使用的变量(已处理文件的数量)。
但它没有用。然后我甚至创建了另一个线程,我在前一个线程之后开始,只重新绘制标签。仍然没有任何作用。
代码是这样的:
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try { SwingUtilities.invokeLater(validateFiles); }
}); }
Runnable validateFiles = new Runnable() {
@Override
public void run() {
while(x_is_not_100) {
processLoadsOfStuff();
label.setText(x); }
}
};
你能帮我解决这个问题吗?
答案 0 :(得分:7)
简单 - 使用SwingWorker
。有关更多信息,请阅读Tasks that Have Interim Results教程。
以下是一个非常通用的示例,它将使用JLabel
来显示从 0 到 30 的计数 -
public final class SwingWorkerDemo {
private static JLabel label =
new JLabel(String.valueOf(0), SwingConstants.CENTER);
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
createAndShowGUI();
}
});
JLabelSwingWorker workerThread = new JLabelSwingWorker();
workerThread.run();
}
private static void createAndShowGUI(){
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static class JLabelSwingWorker extends SwingWorker<Void, Integer>{
@Override
protected Void doInBackground() throws Exception {
for(int i = 1; i < 31; i++){
Thread.sleep(1000);
publish(i);
}
return null;
}
@Override
protected void process(List<Integer> integers) {
Integer i = integers.get(integers.size() - 1);
label.setText(i.toString());
}
}
}
答案 1 :(得分:6)
后台处理必须在单独的线程中完成。但标签更新必须在事件派发线程中完成。
所以你的代码应该是这样的:
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// start a new thread for the background task
new Thread(validateFiles).start();
});
}
Runnable validateFiles = new Runnable() {
@Override
public void run() {
while(x_is_not_100) {
processLoadsOfStuff();
// use SwingUtilities.invokeLater so that the label update is done in the EDT:
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
label.setText(x);
}
});
}
};
但您可能希望使用SwingWorker
类,它旨在以更简单的方式执行此操作。它的文档做得很好,包含了一些例子。