自定義 LoadingGlassPane 繼承 JPanel,設置為 JFrame 的 GlassPane。啟用時顯示「讀取中...」文字與動態 GIF,背景透明,用戶可看到底層介面但無法點擊操作。

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class LoadingGlassPane extends JPanel {
private static final long serialVersionUID = 1L;
private JLabel statusLabel = new JLabel("Reading data, please wait...");
public LoadingGlassPane() {
try {
statusLabel.setIcon(new ImageIcon(getClass().getResource("loading.gif")));
} catch (RuntimeException e) { e.printStackTrace(); }
statusLabel.setHorizontalAlignment(JLabel.CENTER);
// 必須添加滑鼠監聽器消費事件,否則事件會穿透到底層組件
this.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {}
});
this.setLayout(new BorderLayout());
this.add(statusLabel);
setOpaque(false); // 透明背景
}
public void setStatusText(final String text) {
SwingUtilities.invokeLater(() -> statusLabel.setText(text));
}
public void installAsGlassPane(JFrame frame) {
frame.setGlassPane(this);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Test GlassPane");
final LoadingGlassPane glassPane = new LoadingGlassPane();
glassPane.installAsGlassPane(frame);
JButton button = new JButton("Test Query");
button.addActionListener(e -> {
new Thread(() -> {
glassPane.setVisible(true);
glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
try { Thread.sleep(2000); } // 模擬耗時操作
catch (InterruptedException ex) { ex.printStackTrace(); }
glassPane.setCursor(Cursor.getDefaultCursor());
glassPane.setVisible(false);
}).start();
});
frame.setLayout(new FlowLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(button);
frame.setSize(200, 200);
frame.setVisible(true);
}
}
setOpaque(false) 實現透明背景MouseListener 攔截滑鼠事件,防止穿透SwingUtilities.invokeLater 確保 UI 更新在 EDT 執行WAIT_CURSOR 提升用戶體驗Oracle 官方教程:How to Use Root Panes