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

Java Swing添加大型组件时实时更新GUI进度的问题

问题原因

你的代码把所有耗时的组件创建、添加操作都放在了**事件调度线程(EDT)**中。EDT负责处理所有UI更新和用户事件,一旦被耗时操作阻塞,就无法及时响应UI刷新请求,导致进度标签的更新只能等到所有组件加载完成后才会一次性显示。

解决方案:使用SwingWorker

SwingWorker专门用于处理耗时任务,它会在后台线程执行耗时操作,同时自动在EDT中安全更新UI,既解决了EDT阻塞问题,也不会造成代码嵌套混乱。

修改后的代码示例

import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class Test {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            // 初始化基础UI
            final JFrame frame = new JFrame();
            final Container contentPane = frame.getContentPane();
            contentPane.setLayout(new FlowLayout(FlowLayout.LEFT));
            final JLabel loadingLabel = new JLabel("Loading 0/5");
            contentPane.add(loadingLabel);

            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);

            // 创建并启动SwingWorker处理耗时任务
            new SwingWorker<Void, Object[]>() {
                @Override
                protected Void doInBackground() throws Exception {
                    // 后台线程执行耗时的大型组件创建
                    for (int i = 1; i <= 5; i++) {
                        long time = System.currentTimeMillis();
                        JPanel bigPanel = getBigJPanel();
                        // 向EDT发布进度值和创建好的组件
                        publish(new Object[]{i, bigPanel});
                        System.out.println("time <i=" + i + ">: " + (System.currentTimeMillis() - time));
                    }
                    return null;
                }

                @Override
                protected void process(List<Object[]> chunks) {
                    // 此方法自动在EDT中执行,安全更新UI
                    for (Object[] chunk : chunks) {
                        int progress = (Integer) chunk[0];
                        JPanel bigPanel = (JPanel) chunk[1];
                        // 更新进度标签
                        loadingLabel.setText("Loading " + progress + "/5");
                        // 将组件添加到界面
                        contentPane.add(bigPanel);
                        // 刷新界面布局和绘制
                        contentPane.revalidate();
                        contentPane.repaint();
                    }
                }

                @Override
                protected void done() {
                    // 任务完成后的收尾操作
                    loadingLabel.setText("加载完成");
                }
            }.execute();
        });
    }

    private static JPanel getBigJPanel() {
        final JPanel panel = new JPanel();
        panel.setPreferredSize(new Dimension(300, 300));
        for (int i = 0; i < 25_000; i++) {
            panel.add(new JPanel());
        }
        return panel;
    }
}

代码说明

  • doInBackground(): 在独立的后台线程运行,负责创建大型组件,完全不会阻塞EDT。每次组件创建完成后,通过publish()把进度值和组件对象传递给EDT。
  • process(): 自动在EDT中执行,接收后台线程传递的数据,完成进度标签更新、组件添加和界面刷新,确保UI操作的安全性和实时性。
  • done(): 任务全部完成后在EDT中执行,可用于完成收尾提示(比如修改标签文本为"加载完成")。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 19:53:41