Swing 中的所有繁重任务都应该由SwingWorkers执行。否则,大任务会给事件调度线程带来困难,因此事件无法发生(GUI 将冻结)。
因此,您必须创建一个SwingWorker
并以百分比计算任务的已完成步骤,并将值赋给进度条。但是,您必须记住,由于progressbar.setValue(int value)
是组件更新,它应该只发生在 EDT 内部。这就是为什么你必须使用publish
和process
工人的方法。
让我们看一个示例,我们必须在 Desktop 中将 1000 行写入文本文件并查看其进度。这是一个“大任务”(我让线程休眠),所以它符合我们的情况。
public class ProgressExample extends JFrame {
private static final long serialVersionUID = 5326278833296436018L;
public ProgressExample() {
super("test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(new ProgressPanel());
pack();
setLocationRelativeTo(null);
}
private static class WriteTextWorker extends SwingWorker<Void, Integer> {
private ProgressableView view;
public WriteTextWorker(ProgressableView view) {
this.view = view;
}
@Override
protected void process(List<Integer> chunks) {
int progress = chunks.get(0);
view.setProgress(progress);
}
@Override
protected Void doInBackground() throws Exception {
publish(0);
File desktop = new File(System.getProperty("user.home"), "Desktop");
File textFile = new File(desktop, "stackoverflow.txt");
int linesToWrite = 1000;
try (FileWriter fw = new FileWriter(textFile, true);
BufferedWriter bw = new BufferedWriter(fw);
PrintWriter out = new PrintWriter(bw)) {
for (int i = 0; i < linesToWrite; i++) {
out.println("This is line: " + i);
out.flush();
//Calculate percentage of completed task
int percentage = ((i * 100) / linesToWrite);
System.out.println("Percentage: " + percentage);
publish(percentage);
Thread.sleep(10); //Heavy task
}
}
return null;
}
}
private static class ProgressPanel extends JPanel implements ProgressableView {
private JProgressBar progressBar;
private SwingWorker<Void, Integer> worker;
public ProgressPanel() {
super(new BorderLayout());
progressBar = new JProgressBar();
add(progressBar, BorderLayout.PAGE_START);
JButton writeLinesButton = new JButton("Press me to do a long task");
writeLinesButton.addActionListener(e -> worker.execute());
add(writeLinesButton, BorderLayout.PAGE_END);
worker = new WriteTextWorker(this);
}
@Override
public int getProgress() {
return progressBar.getValue();
}
@Override
public void setProgress(int progress) {
progressBar.setValue(progress);
}
}
public static interface ProgressableView {
int getProgress();
void setProgress(int progress);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new ProgressExample().setVisible(true));
}
}