在 Swing 桌面應用中,根據文件擴展名獲取系統原生圖標(小圖標 16×16、大圖標 32×32/48×48)能顯著提升用戶體驗。本文展示基於 FileSystemView(跨平台小圖標)與 ShellFolder(Windows 大圖標)的組合方案。
import javax.swing.*;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
import sun.awt.shell.ShellFolder; // 內部 API,僅 Windows
public class FileIconExtractor extends JFrame implements ActionListener {
private JButton getIconBtn = new JButton("Get Icon");
private JPanel iconPanel = new JPanel();
private JTextField extField = new JTextField();
private JLabel smallIconLabel = new JLabel("Small Icon");
private JLabel bigIconLabel = new JLabel("Big Icon");
public FileIconExtractor() {
setSize(400, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new BorderLayout());
getIconBtn.setActionCommand("GETICON");
getIconBtn.addActionListener(this);
iconPanel.setLayout(new BoxLayout(iconPanel, BoxLayout.Y_AXIS));
iconPanel.add(smallIconLabel);
iconPanel.add(bigIconLabel);
add(extField, BorderLayout.NORTH);
add(iconPanel, BorderLayout.CENTER);
add(getIconBtn, BorderLayout.SOUTH);
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
if ("GETICON".equals(e.getActionCommand())) {
String ext = extField.getText().trim();
if (ext.isEmpty()) return;
try {
// 1. 創建臨時文件(帶目標擴展名)
File file = File.createTempFile("icon", "." + ext);
// 2. 獲取小圖標(跨平台,FileSystemView)
FileSystemView fsv = FileSystemView.getFileSystemView();
Icon smallIcon = fsv.getSystemIcon(file);
// 3. 獲取大圖標(Windows 專用,ShellFolder)
Icon bigIcon = null;
try {
ShellFolder shellFolder = ShellFolder.getShellFolder(file);
bigIcon = new ImageIcon(shellFolder.getIcon(true)); // true=大圖標
} catch (Exception ex) {
// 非 Windows 或獲取失敗,回退小圖標放大
bigIcon = smallIcon;
}
// 4. 顯示
smallIconLabel.setIcon(smallIcon);
smallIconLabel.setText("Small (16x16): " + ext);
bigIconLabel.setIcon(bigIcon);
bigIconLabel.setText("Large (32x32+): " + ext);
// 5. 清理臨時文件
file.delete();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(FileIconExtractor::new);
}
}
| API | 包來源 | 平台 | 圖標尺寸 | 用途 |
|---|---|---|---|---|
FileSystemView.getSystemIcon() |
javax.swing.filechooser | 跨平台 | 16×16 (小) | 通用文件列表、樹形圖標 |
ShellFolder.getShellFolder().getIcon(true) |
sun.awt.shell (內部) | 僅 Windows | 32×32/48×48 (大) | Windows 風格大圖標視圖 |
sun.* 包不保證跨版本兼容,JDK 9+ 模組化後需 --add-exports 或反射調用Map,避免重複創建臨時文件ShellFolder.getIcon(true) 通常返回系統當前 DPI 對應尺寸// 編譯/運行需添加導出
--add-exports java.desktop/sun.awt.shell=ALL-UNNAMED
// 或反射調用(不需編譯時依賴)
Class> shellFolderClass = Class.forName("sun.awt.shell.ShellFolder");
Method getShellFolder = shellFolderClass.getDeclaredMethod("getShellFolder", File.class);
Object shellFolder = getShellFolder.invoke(null, file);
Method getIcon = shellFolderClass.getDeclaredMethod("getIcon", boolean.class);
Icon bigIcon = (Icon) getIcon.invoke(shellFolder, true);
獲取系統原生文件圖標是桌面應用專業度的細節體現。組合 FileSystemView(跨平台基礎)與 ShellFolder(Windows 增強),配合緩存與回退策略,能構建健壯的圖標服務層。