You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Swing中从菜单项ActionListener触发JProgressBar不显示的问题

核心问题根源

Swing 所有UI组件的绘制、事件响应、状态更新操作都由*事件分发线程(EDT)*统一处理,该线程绝对不能被阻塞。

  • 菜单项的 actionPerformed 回调默认运行在EDT线程上,此时直接调用 Process() 方法,会把包含 Thread.sleep() 的循环逻辑全部放在EDT上执行,直接将EDT完全阻塞。
  • 被阻塞的EDT无法执行组件布局、绘制任务,因此进度指示器窗口仅能弹出框架,内部的 JProgressBar 无法完成渲染;同时通过 SwingUtilities.invokeLater 提交的进度更新任务,也因为EDT被卡住,根本没有执行机会。
  • 直接在Main2构造器中调用 Process() 时,整个程序运行在主线程,循环和休眠操作不会占用EDT资源,EDT可以正常完成UI绘制、更新,因此功能表现正常。
修正方案

严格遵循Swing线程规则拆分任务:

  • 所有UI组件的创建、显示、状态修改操作,必须提交到EDT执行。
  • 所有带循环、休眠、IO的耗时操作,必须放到独立的工作线程运行,不能阻塞EDT。

修正后的Process方法示例

private void Process() {
    // 进度条初始化、显示逻辑提交到EDT执行
    SwingUtilities.invokeLater(() -> {
        pi = new jpcProgressIndicator();
        pi.setTitle("Progress of Growth & Persistency");
        pi.Update(0);
        pi.Show(true);
    });

    // 耗时循环逻辑放到独立工作线程,避免阻塞EDT
    new Thread(() -> {
        int nCounter = 0;
        while (nCounter < 100) {
            final int currentValue = nCounter;
            try {
                // 进度值更新提交到EDT执行
                SwingUtilities.invokeLater(() -> pi.Update(currentValue));
                Thread.sleep(100);
            } catch (InterruptedException e) {
                System.out.println("Error: " + e.getMessage());
            }
            nCounter++;
        }
        // 窗口关闭逻辑提交到EDT执行
        SwingUtilities.invokeLater(() -> pi.Close());
    }).start();
}

生产环境可使用 SwingWorker 替代普通工作线程,其内置的进度发布、任务完成回调机制能更好适配Swing线程模型,减少重复提交UI更新任务的代码量。


内容的提问来源于stack exchange,提问作者Jon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.27 16:36:03