首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 多媒體程式設計:影像、音效、字型與色彩完整應用指南

     編輯:Java 程式設計入門

前言:讓程式擁有視覺與聽覺魅力

純文字介面雖然高效,但缺乏直觀吸引力。Java 提供豐富的多媒體 API,讓開發者能輕鬆整合影像、音效、字型與色彩,打造生動的使用者體驗。本章將系統介紹 java.awt、javax.swing、java.applet 等套件的多媒體處理能力,並提供實用的最佳實踐模式。

11.1 影像處理:從載入到顯示

支援格式與核心類別

格式副檔名特色
JPEG.jpg, .jpeg有損壓縮、適合照片、不支援透明
PNG.png無損壓縮、支援 Alpha 透明、適合圖示/介面
GIF.gif256 色、支援動畫、單色透明
BMP.bmp無壓縮、檔案大、相容性佳
WBMP.wbmp無線位圖、行動裝置專用

核心類別:

  • java.awt.Image — 抽象影像類別,代表像素資料
  • javax.swing.ImageIcon — Swing 元件專用影像包裝,可直接套用於 JLabel、JButton 等
  • java.awt.Toolkit — getImage(url) 非同步載入
  • javax.imageio.ImageIO — 推薦,同步讀寫、格式轉換、元資料處理

三步驟顯示影像


// 1. 載入影像 (推薦使用 ImageIO 同步載入,確保完整讀取)
Image rawImage = ImageIO.read(new File("photo.jpg")); 
// 或從 classpath 載入(打包成 JAR 時適用)
// Image rawImage = ImageIO.read(getClass().getResource("/images/photo.jpg"));

// 2. 包裝為 ImageIcon
ImageIcon icon = new ImageIcon(rawImage);

// 3. 套用至元件
JLabel label = new JLabel(icon);
JButton btn = new JButton("帶圖示按鈕", icon);
btn.setHorizontalTextPosition(SwingConstants.CENTER);
btn.setVerticalTextPosition(SwingConstants.BOTTOM); // 文字在圖示下方

進階:按鈕狀態圖示


JButton toggleBtn = new JButton();
toggleBtn.setIcon(new ImageIcon(ImageIO.read(new File("off.png"))));       // 正常
toggleBtn.setRolloverIcon(new ImageIcon(ImageIO.read(new File("hover.png")))); // 滑鼠懸停
toggleBtn.setPressedIcon(new ImageIcon(ImageIO.read(new File("pressed.png")))); // 按下
toggleBtn.setSelectedIcon(new ImageIcon(ImageIO.read(new File("on.png"))));     // 選中狀態
toggleBtn.setDisabledIcon(new ImageIcon(ImageIO.read(new File("disabled.png")))); // 停用

完整範例:影像檢視器


public class ImageViewer extends JFrame {
    private JLabel imageLabel = new JLabel();
    private JFileChooser fileChooser = new JFileChooser();
    private FileNameExtensionFilter imgFilter = 
        new FileNameExtensionFilter("影像檔案", "jpg", "jpeg", "png", "gif", "bmp");

    public ImageViewer() {
        setTitle("影像檢視器");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
        
        // 中央顯示區,支援捲動
        JScrollPane scrollPane = new JScrollPane(imageLabel);
        scrollPane.getViewport().setBackground(Color.DARK_GRAY);
        add(scrollPane, BorderLayout.CENTER);
        
        // 底部工具列
        JPanel toolbar = new JPanel(new FlowLayout(FlowLayout.LEFT));
        JButton openBtn = new JButton("開啟影像");
        JButton zoomInBtn = new JButton("放大 (+)");
        JButton zoomOutBtn = new JButton("縮小 (-)");
        JButton resetBtn = new JButton("原始大小");
        toolbar.add(openBtn); toolbar.add(zoomInBtn); toolbar.add(zoomOutBtn); toolbar.add(resetBtn);
        add(toolbar, BorderLayout.SOUTH);
        
        // 事件處理
        openBtn.addActionListener(e -> openImage());
        zoomInBtn.addActionListener(e -> scaleImage(1.25));
        zoomOutBtn.addActionListener(e -> scaleImage(0.8));
        resetBtn.addActionListener(e -> resetImage());
        
        fileChooser.setFileFilter(imgFilter);
        fileChooser.setCurrentDirectory(new File(System.getProperty("user.home"), "Pictures"));
        
        pack();
        setSize(800, 600);
        setLocationRelativeTo(null);
        setVisible(true);
    }
    
    private Image originalImage;
    private double scale = 1.0;
    
    private void openImage() {
        if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            try {
                originalImage = ImageIO.read(fileChooser.getSelectedFile());
                scale = 1.0;
                updateDisplay();
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(this, "無法讀取檔案: " + ex.getMessage(), "錯誤", JOptionPane.ERROR_MESSAGE);
            }
        }
    }
    
    private void scaleImage(double factor) {
        if (originalImage != null) {
            scale *= factor;
            updateDisplay();
        }
    }
    
    private void resetImage() {
        scale = 1.0;
        updateDisplay();
    }
    
    private void updateDisplay() {
        if (originalImage == null) return;
        int w = (int)(originalImage.getWidth(null) * scale);
        int h = (int)(originalImage.getHeight(null) * scale);
        Image scaled = originalImage.getScaledInstance(w, h, Image.SCALE_SMOOTH);
        imageLabel.setIcon(new ImageIcon(scaled));
        imageLabel.setText(null); // 清除文字
        revalidate(); // 更新捲動區域
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(ImageViewer::new);
    }
}

URL 載入與 getCodeBase() 替代方案

現代應用較少使用 Applet,桌面程式推薦:

  • 檔案系統:new File("path/to/image.png") 或 Paths.get(...)
  • Classpath 資源:getClass().getResource("/images/logo.png")(打包 JAR 內資源)
  • 網路 URL:new URL("https://example.com/image.jpg") 配合 ImageIO.read(url)

11.2 音效播放:簡單易用的音訊 API

支援格式與核心類別

注意:標準 Java Sound API 不直接支援 MP3,需外掛庫(如 JLayer、JOrbis、Tritonus)或使用 JavaFX MediaPlayer。

Applet 相容 API (java.applet.AudioClip)


// 適用於短小音效,記憶體完整載入
AudioClip clip = Applet.newAudioClip(getClass().getResource("/sounds/click.wav"));
clip.play();      // 播放一次
clip.loop();      // 循環播放
clip.stop();      // 停止

進階:Java Sound API (javax.sound.sampled) — 精確控制


import javax.sound.sampled.*;

public class SoundPlayer {
    private Clip clip;
    private FloatControl volumeControl;
    
    public void load(String resourcePath) {
        try {
            AudioInputStream ais = AudioSystem.getAudioInputStream(
                getClass().getResource(resourcePath));
            clip = AudioSystem.getClip();
            clip.open(ais);
            volumeControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
        } catch (Exception e) { e.printStackTrace(); }
    }
    
    public void play() {
        if (clip != null) {
            clip.setFramePosition(0); // 重頭播放
            clip.start();
        }
    }
    
    public void loop() { if (clip != null) clip.loop(Clip.LOOP_CONTINUOUSLY); }
    public void stop() { if (clip != null) clip.stop(); }
    
    public void setVolume(float level) { // 0.0 ~ 1.0
        if (volumeControl != null) {
            float min = volumeControl.getMinimum();
            float max = volumeControl.getMaximum();
            volumeControl.setValue(min + (max - min) * level);
        }
    }
}

// 使用範例
SoundPlayer bgm = new SoundPlayer();
bgm.load("/music/background.wav");
bgm.setVolume(0.5f);
bgm.loop();

// 遊戲音效
SoundPlayer jumpSfx = new SoundPlayer();
jumpSfx.load("/sfx/jump.wav");
jumpSfx.play();

完整範例:簡易音樂播放器


public class MiniPlayer extends JFrame {
    private SoundPlayer player = new SoundPlayer();
    private JSlider volumeSlider = new JSlider(0, 100, 50);
    private JLabel statusLabel = new JLabel("未載入音樂");
    private File currentFile;

    public MiniPlayer() {
        setTitle("迷你播放器");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new BorderLayout(10, 10));
        
        // 控制面板
        JPanel ctrlPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 15, 10));
        JButton loadBtn = new JButton("載入");
        JButton playBtn = new JButton("播放");
        JButton pauseBtn = new JButton("暫停");
        JButton stopBtn = new JButton("停止");
        JButton loopBtn = new JButton("循環");
        ctrlPanel.add(loadBtn); ctrlPanel.add(playBtn); ctrlPanel.add(pauseBtn); 
        ctrlPanel.add(stopBtn); ctrlPanel.add(loopBtn);
        
        // 音量控制
        JPanel volPanel = new JPanel(new BorderLayout(5, 5));
        volPanel.setBorder(BorderFactory.createTitledBorder("音量"));
        volPanel.add(new JLabel("小"), BorderLayout.WEST);
        volPanel.add(volumeSlider, BorderLayout.CENTER);
        volPanel.add(new JLabel("大"), BorderLayout.EAST);
        
        JPanel southPanel = new JPanel(new BorderLayout());
        southPanel.add(ctrlPanel, BorderLayout.NORTH);
        southPanel.add(volPanel, BorderLayout.CENTER);
        southPanel.add(statusLabel, BorderLayout.SOUTH);
        add(southPanel, BorderLayout.SOUTH);
        
        // 事件
        loadBtn.addActionListener(e -> loadFile());
        playBtn.addActionListener(e -> { if (player.clip != null) player.play(); });
        pauseBtn.addActionListener(e -> { if (player.clip != null) player.clip.stop(); });
        stopBtn.addActionListener(e -> { if (player.clip != null) { player.clip.stop(); player.clip.setFramePosition(0); } });
        loopBtn.addActionListener(e -> { if (player.clip != null) player.loop(); });
        volumeSlider.addChangeListener(e -> player.setVolume(volumeSlider.getValue() / 100f));
        
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }
    
    private void loadFile() {
        JFileChooser fc = new JFileChooser();
        fc.setFileFilter(new FileNameExtensionFilter("音訊檔", "wav", "aif", "au"));
        if (fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            currentFile = fc.getSelectedFile();
            try {
                player.load(currentFile.toURI().toURL().toString());
                statusLabel.setText("已載入: " + currentFile.getName());
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(this, "載入失敗: " + ex.getMessage());
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(MiniPlayer::new);
    }
}

11.3 字型設定:排版美學的關鍵

字型三要素

  1. 字型家族:Font.SANS_SERIF (無襯線)、Font.SERIF (襯線)、Font.MONOSPACED (等寬)、或系統安裝字型名稱("微軟正黑體"、"Noto Sans CJK TC"、"Arial"
  2. 樣式:Font.PLAIN、Font.BOLD、Font.ITALIC、Font.BOLD | Font.ITALIC
  3. 大小:單位為 點 (pt),1 pt = 1/72 英吋

建立與套用字型


// 建構字型
Font titleFont = new Font("微軟正黑體", Font.BOLD, 28);
Font codeFont = new Font(Font.MONOSPACED, Font.PLAIN, 14);
Font chineseFont = new Font("Noto Sans CJK TC", Font.PLAIN, 16); // 跨平台開源中文字型

// 套用至元件
label.setFont(titleFont);
textArea.setFont(codeFont);
button.setFont(chineseFont);

// 取得系統可用字型
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
String[] fontNames = ge.getAvailableFontFamilyNames();
for (String name : fontNames) System.out.println(name);

字型度量與文字渲染進階


Font font = new Font("微軟正黑體", Font.PLAIN, 16);
FontMetrics fm = getFontMetrics(font); // 需在 Component 內呼叫

int width = fm.stringWidth("Hello World"); // 文字寬度
int height = fm.getHeight();               // 行高
int ascent = fm.getAscent();               // 基線以上高度
int descent = fm.getDescent();             // 基線以下高度
int leading = fm.getLeading();             // 行間距

// 繪製置中文字 (在 paintComponent 中)
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;
    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    g2d.setFont(font);
    String text = "置中文字";
    FontMetrics fm2 = g2d.getFontMetrics();
    int x = (getWidth() - fm2.stringWidth(text)) / 2;
    int y = (getHeight() + fm2.getAscent()) / 2;
    g2d.drawString(text, x, y);
}

完整範例:字型大小漸變展示


public class FontDemo extends JFrame {
    public FontDemo() {
        setTitle("字型大小漸變示範");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new GridLayout(0, 1, 5, 5));
        
        String[] fonts = {"微軟正黑體", "新細明體", "標楷體", "Arial", "Noto Sans CJK TC"};
        JComboBox fontChooser = new JComboBox<>(fonts);
        fontChooser.addActionListener(e -> updateLabels());
        add(fontChooser, BorderLayout.NORTH);
        
        JPanel labelPanel = new JPanel();
        labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.Y_AXIS));
        for (int size = 10; size <= 48; size += 2) {
            JLabel label = new JLabel("字型大小: " + size + "pt - The quick brown fox");
            label.setAlignmentX(Component.LEFT_ALIGNMENT);
            labelPanel.add(label);
        }
        JScrollPane scroll = new JScrollPane(labelPanel);
        add(scroll, BorderLayout.CENTER);
        
        pack();
        setSize(600, 500);
        setLocationRelativeTo(null);
        setVisible(true);
    }
    
    private void updateLabels() {
        // 實作略
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(FontDemo::new);
    }
}

11.4 色彩運用:從預定義到自訂調色

Color 類別核心功能

格式副檔名適用場景
WAV.wav無損、短音效、遊戲音效、系統提示音
AIFF.aif, .aiffMac 標準、無損
AU.auSun/Unix 標準、早期 Java 預設
MIDI.mid, .midi樂器數據、檔案極小、背景音樂
建立方式語法範例說明
預定義常數Color.RED, Color.BLUE, Color.WHITE...13 種基本顏色 + 淺/深灰階
RGB 整數new Color(255, 128, 0)紅綠藍各 0-255,共 1677 萬色
RGBA 整數new Color(255, 0, 0, 128)含 Alpha 透明度 (0 透明 ~ 255 不透明)
RGB 浮點數new Color(1.0f, 0.5f, 0.0f)各分量 0.0~1.0
HSB 色相飽和度亮度Color.getHSBColor(0.5f, 1.0f, 1.0f)H: 0-1 (色相環), S: 0-1, B: 0-1
十六進位Color.decode("#FF8000")Web 標準格式

常用操作方法


Color c = new Color(100, 150, 200);
int r = c.getRed();        // 0-255
int g = c.getGreen();
int b = c.getBlue();
int alpha = c.getAlpha();  // 0-255
int rgb = c.getRGB();      // 0xRRGGBB (不含 alpha)
int argb = c.getRGB();     // 0xAARRGGBB (含 alpha)

// 亮度計算 (sRGB 亮度公式)
float luminance = 0.2126f * r/255 + 0.7152f * g/255 + 0.0722f * b/255;

// 顏色轉換
float[] hsb = Color.RGBtoHSB(r, g, b, null); // 回傳 [h, s, b]
Color brighter = c.brighter();                // 變亮
Color darker = c.darker();                    // 變暗

// 透明度處理
Color semiTransparent = new Color(r, g, b, 128); // 50% 透明
// 或
Color translucent = new Color(c.getRGB() & 0x00FFFFFF, true); // 保留 RGB,設 alpha=0

UI 設計色彩原則

  1. 對比度:文字與背景亮度差 ≥ 4.5:1 (WCAG AA 級)
  2. 色彩心理:藍=信任/科技、紅=警示/熱情、綠=成功/自然、黃=警告/活力
  3. 色盲友善:避免紅綠搭配表達關鍵資訊,使用圖示/文字輔助
  4. 主題系統:定義 Primary/Secondary/Background/Surface/Error 色系,支援深色模式

完整範例:調色盤工具


public class ColorPickerTool extends JFrame {
    private JPanel previewPanel = new JPanel();
    private JSlider rSlider = new JSlider(0, 255, 128);
    private JSlider gSlider = new JSlider(0, 255, 128);
    private JSlider bSlider = new JSlider(0, 255, 128);
    private JSlider aSlider = new JSlider(0, 255, 255);
    private JTextField hexField = new JTextField(8);
    private JTextField rgbField = new JTextField(20);

    public ColorPickerTool() {
        setTitle("RGB 調色盤");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new BorderLayout(10, 10));
        
        // 預覽區
        previewPanel.setPreferredSize(new Dimension(300, 200));
        previewPanel.setBorder(BorderFactory.createTitledBorder("預覽"));
        previewPanel.setBackground(new Color(128, 128, 128));
        add(previewPanel, BorderLayout.NORTH);
        
        // 滑桿控制區
        JPanel sliderPanel = new JPanel(new GridLayout(4, 2, 5, 5));
        sliderPanel.setBorder(BorderFactory.createTitledBorder("RGBA 控制"));
        addSliderRow(sliderPanel, "紅 (R):", rSlider);
        addSliderRow(sliderPanel, "綠 (G):", gSlider);
        addSliderRow(sliderPanel, "藍 (B):", bSlider);
        addSliderRow(sliderPanel, "透明度 (A):", aSlider);
        add(sliderPanel, BorderLayout.CENTER);
        
        // 數值輸出區
        JPanel outputPanel = new JPanel(new GridLayout(2, 2, 5, 5));
        outputPanel.setBorder(BorderFactory.createTitledBorder("色碼輸出"));
        outputPanel.add(new JLabel("HEX:")); outputPanel.add(hexField);
        outputPanel.add(new JLabel("RGB:")); outputPanel.add(rgbField);
        hexField.setEditable(false); rgbField.setEditable(false);
        add(outputPanel, BorderLayout.SOUTH);
        
        // 事件綁定
        ChangeListener listener = e -> updateColor();
        rSlider.addChangeListener(listener);
        gSlider.addChangeListener(listener);
        bSlider.addChangeListener(listener);
        aSlider.addChangeListener(listener);
        
        updateColor();
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }
    
    private void addSliderRow(JPanel panel, String label, JSlider slider) {
        panel.add(new JLabel(label));
        slider.setMajorTickSpacing(51);
        slider.setMinorTickSpacing(17);
        slider.setPaintTicks(true);
        slider.setPaintLabels(true);
        panel.add(slider);
    }
    
    private void updateColor() {
        Color c = new Color(rSlider.getValue(), gSlider.getValue(), 
                           bSlider.getValue(), aSlider.getValue());
        previewPanel.setBackground(c);
        
        // HEX 格式 #RRGGBB 或 #AARRGGBB
        String hex = String.format("#%02X%02X%02X%02X", 
            c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha());
        hexField.setText(hex);
        
        // RGB 格式
        String rgb = String.format("rgb(%d, %d, %d)%s", 
            c.getRed(), c.getGreen(), c.getBlue(), 
            c.getAlpha() < 255 ? String.format(" / alpha=%d", c.getAlpha()) : "");
        rgbField.setText(rgb);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(ColorPickerTool::new);
    }
}

11.5 綜合實戰:多媒體豐富的設定對話框


public class SettingsDialog extends JDialog {
    public SettingsDialog(Frame owner) {
        super(owner, "系統設定", true);
        setLayout(new BorderLayout(10, 10));
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        
        // 標題區:Logo + 標題
        JPanel header = new JPanel(new BorderLayout());
        header.setBackground(new Color(0x2C3E50));
        header.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        
        try {
            Image logoImg = ImageIO.read(getClass().getResource("/images/logo.png"));
            JLabel logoLabel = new JLabel(new ImageIcon(logoImg.getScaledInstance(64, 64, Image.SCALE_SMOOTH)));
            header.add(logoLabel, BorderLayout.WEST);
        } catch (Exception e) {
            header.add(new JLabel("⚙"), BorderLayout.WEST);
        }
        
        JLabel titleLabel = new JLabel("系統設定");
        titleLabel.setFont(new Font("微軟正黑體", Font.BOLD, 24));
        titleLabel.setForeground(Color.WHITE);
        header.add(titleLabel, BorderLayout.CENTER);
        add(header, BorderLayout.NORTH);
        
        // 內容區:分頁面板
        JTabbedPane tabs = new JTabbedPane();
        tabs.addTab("外觀", createAppearancePanel());
        tabs.addTab("音效", createSoundPanel());
        tabs.addTab("字型", createFontPanel());
        tabs.addTab("色彩", createColorPanel());
        add(tabs, BorderLayout.CENTER);
        
        // 底部按鈕
        JPanel btnPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        JButton okBtn = new JButton("確定");
        JButton cancelBtn = new JButton("取消");
        JButton applyBtn = new JButton("套用");
        okBtn.addActionListener(e -> dispose());
        cancelBtn.addActionListener(e -> dispose());
        applyBtn.addActionListener(e -> applySettings());
        btnPanel.add(applyBtn); btnPanel.add(okBtn); btnPanel.add(cancelBtn);
        add(btnPanel, BorderLayout.SOUTH);
        
        pack();
        setSize(600, 500);
        setLocationRelativeTo(owner);
        setVisible(true);
    }
    
    private JPanel createAppearancePanel() {
        JPanel p = new JPanel(new GridLayout(0, 1, 10, 10));
        p.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        p.add(new JCheckBox("深色模式"));
        p.add(new JCheckBox("顯示工具列圖示"));
        p.add(new JCheckBox("啟用動畫效果"));
        return p;
    }
    
    private JPanel createSoundPanel() {
        JPanel p = new JPanel(new GridLayout(0, 1, 10, 10));
        p.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        p.add(new JCheckBox("啟用系統音效"));
        JSlider vol = new JSlider(0, 100, 70);
        vol.setMajorTickSpacing(25);
        vol.setPaintTicks(true);
        vol.setPaintLabels(true);
        p.add(new JLabel("主音量:"));
        p.add(vol);
        return p;
    }
    
    private JPanel createFontPanel() {
        JPanel p = new JPanel(new GridBagLayout());
        p.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.anchor = GridBagConstraints.WEST;
        
        String[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
        JComboBox fontBox = new JComboBox<>(fonts);
        JSpinner sizeSpinner = new JSpinner(new SpinnerNumberModel(14, 8, 72, 1));
        
        gbc.gridx = 0; gbc.gridy = 0; p.add(new JLabel("字型:"), gbc);
        gbc.gridx = 1; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 1.0; p.add(fontBox, gbc);
        gbc.gridx = 0; gbc.gridy = 1; gbc.fill = GridBagConstraints.NONE; gbc.weightx = 0; p.add(new JLabel("大小:"), gbc);
        gbc.gridx = 1; gbc.fill = GridBagConstraints.HORIZONTAL; p.add(sizeSpinner, gbc);
        
        // 預覽
        JLabel preview = new JLabel("預覽文字: The quick brown fox jumps over the lazy dog");
        preview.setFont(new Font("微軟正黑體", Font.PLAIN, 14));
        gbc.gridx = 0; gbc.gridy = 2; gbc.gridwidth = 2; gbc.fill = GridBagConstraints.HORIZONTAL;
        p.add(preview, gbc);
        
        ChangeListener updater = e -> preview.setFont(new Font(
            (String)fontBox.getSelectedItem(), Font.PLAIN, (Integer)sizeSpinner.getValue()));
        fontBox.addActionListener(updater);
        sizeSpinner.addChangeListener(updater);
        
        return p;
    }
    
    private JPanel createColorPanel() {
        JPanel p = new JPanel(new GridLayout(0, 2, 10, 10));
        p.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        
        String[] colorRoles = {"主色調", "次要色", "背景色", "文字色", "錯誤色", "成功色"};
        for (String role : colorRoles) {
            p.add(new JLabel(role + ":"));
            JButton colorBtn = new JButton("選擇顏色");
            colorBtn.addActionListener(e -> {
                Color c = JColorChooser.showDialog(this, "選擇 " + role, Color.WHITE);
                if (c != null) colorBtn.setBackground(c);
            });
            p.add(colorBtn);
        }
        return p;
    }
    
    private void applySettings() {
        // 實際儲存設定至 Preferences 或設定檔
        System.out.println("設定已套用");
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new SettingsDialog(null));
    }
}

效能與部署建議

  1. 影像快取:重複使用的圖示載入一次快取於 Map
  2. 非同步載入:大型影像/音效使用 SwingWorker 背景載入,避免阻塞 EDT
  3. 資源打包:將多媒體檔案置於 src/main/resources,透過 getClass().getResource() 存取,打包 JAR 後仍可運作
  4. 記憶體管理:大量影像處理時注意 Image.flush() 釋放原生資源,避免 OOM
  5. 跨平台字型:內嵌開源字型 (如 Noto Sans、Source Han Sans) 確保中文顯示一致性

本章完整涵蓋 Java 多媒體程式設計核心技術:影像載入顯示與縮放、音效播放控制、字型排版渲染、色彩模型與調色工具。掌握這些技能後,可進階學習 Java 2D 繪圖 API、JavaFX Media 媒體框架、OpenGL 整合 (JOGL/LWJGL) 等高階圖形多媒體開發。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved