点击jButton1时如何更新JProgressBar,避免等待FunctionX执行完毕
问题原因
Swing采用单线程设计模型,所有UI更新、事件响应逻辑都默认运行在**事件调度线程(EDT)**中:
- 你当前的
jButton1ActionPerformed方法本身就在EDT中执行 - 调用
jProgressBar1.setValue后,UI重绘请求会被加入EDT的任务队列等待执行 - 后续的耗时方法
FunctionX()直接阻塞了EDT,队列中的进度条重绘任务直到FunctionX执行完成后才会被调度,因此看不到中间的进度更新
正确实现方案
使用SwingWorker把耗时任务放到后台线程执行,进度更新再回调到EDT操作即可:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { // 先更新初始进度(在EDT中执行,会立即生效) jProgressBar1.setValue(10); jProgressBar1.setValue(20); // 用SwingWorker执行耗时任务 SwingWorker<Void, Integer> worker = new SwingWorker<Void, Integer>() { @Override protected Void doInBackground() throws Exception { // 后台线程执行耗时逻辑,不会阻塞EDT FunctionX(); return null; } @Override protected void done() { // 任务执行完成后回调到EDT,可更新最终进度 jProgressBar1.setValue(100); } }; worker.execute(); }
如果你的FunctionX执行过程中可以拆分步骤获取实时进度,可以进一步改造实现动态进度更新:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { SwingWorker<Void, Integer> worker = new SwingWorker<Void, Integer>() { @Override protected Void doInBackground() throws Exception { publish(10); publish(20); // 改造FunctionX,执行到不同阶段推送对应进度即可 FunctionX(progress -> publish(progress)); return null; } @Override protected void process(List<Integer> chunks) { // 接收后台推送的进度,在EDT中更新UI int latestProgress = chunks.get(chunks.size() - 1); jProgressBar1.setValue(latestProgress); } @Override protected void done() { jProgressBar1.setValue(100); } }; worker.execute(); }
注意事项
- 所有UI组件的操作必须放到EDT中执行,不要在后台线程直接修改进度条属性
- 所有耗时的业务逻辑必须放到后台线程执行,不要占用EDT造成界面卡顿
内容的提问来源于stack exchange,提问作者Ouahab Abdelwhab
相关产品推荐
相关产品推荐

