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

SWT/JFace 圖片特效實戰:Alpha 漸變與 GIF 動畫播放完整範例

     編輯:Java 相關知識

前言:SWT 圖形處理核心類回顧

SWT(Standard Widget Toolkit)提供 Image、ImageData、ImageLoader、GC(Graphics Context)等核心類,支援像素級操作、Alpha 通道合成、多幀動畫解碼。本文透過兩個完整可執行範例,示範靜態 Alpha 漸變遮罩與GIF 多幀動畫播放的實作細節。

一、範例 1:Alpha 漸變遮罩(從左到右透明度線性遞減)

核心邏輯

  1. 載入 ImageData,建立等大小的 byte[] alphaValues。
  2. 雙層迴圈計算每像素 Alpha:255 - 255 * x / width,左邊不透明、右邊全透明。
  3. 將 alphaValues 寫入 imageData.alphaData,建立帶 Alpha 的 Image。
  4. Canvas + PaintListener 繪製,事件迴圈保持視窗開啟。

完整程式碼

package swt_jface.demo10;

import org.eclipse.swt.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.*;

public class AlphaFadeIn {
    Display display = new Display();
    Shell shell = new Shell(display);

    public AlphaFadeIn() {
        shell.setLayout(new FillLayout());
        final Canvas canvas = new Canvas(shell, SWT.NONE);

        // 1. 載入圖片並建立 Alpha 遮罩
        ImageData imageData = new ImageData("C:/icons/eclipse.jpg");
        byte[] alphaValues = new byte[imageData.height * imageData.width];
        for (int y = 0; y < imageData.height; y++) {
            for (int x = 0; x < imageData.width; x++) {
                alphaValues[y * imageData.width + x] = (byte) (255 - 255 * x / imageData.width);
            }
        }
        imageData.alphaData = alphaValues;
        final Image image = new Image(display, imageData);

        // 2. 繪製監聽器
        canvas.addPaintListener(e -> e.gc.drawImage(image, 10, 10));

        shell.setSize(400, 300);
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) display.sleep();
        }
        display.dispose();
    }

    public static void main(String[] args) { new AlphaFadeIn(); }
}

關鍵點提示

  • ImageData.alphaData 長度必須等於 width * height,否則拋 SWTError。
  • Alpha 值 0=全透明,255=不透明,中間線性插值即可產生漸變。
  • 實際專案中建議將圖片路徑外部化,或用 Class.getResourceAsStream 載入資源檔。

二、範例 2:GIF 多幀動畫播放(背景執行緒 + asyncExec)

架構設計

  • ImageLoader 讀取 GIF,返回 ImageData[],每幀含 delayTime(單位:百分之一秒)、x/y(幀偏移)、disposalMethod。
  • 建立一個目標 Image(畫布大小),GC 繪製每幀到該 Image。
  • 背景執行緒輪詢:計算幀索引 → display.asyncExec 切換到 UI 執行緒繪製幀 → canvas.redraw() 觸發重繪 → Thread.sleep(delayTime * 10)。
  • 視窗關閉時 ShellListener 中斷執行緒,釋放資源。

完整程式碼

package swt_jface.demo10;

import org.eclipse.swt.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.*;

public class Animations {
    Display display = new Display();
    Shell shell = new Shell(display);

    public Animations() {
        shell.setLayout(new FillLayout());

        // 1. 載入 GIF 所有幀
        ImageLoader loader = new ImageLoader();
        final ImageData[] frames = loader.load("C:/icons/eclipse-ani.gif");
        final Image canvasImage = new Image(display, frames[0].width, frames[0].height);
        final GC gc = new GC(canvasImage);

        final Canvas canvas = new Canvas(shell, SWT.NONE);
        canvas.addPaintListener(e -> e.gc.drawImage(canvasImage, 0, 0));

        // 2. 動畫執行緒
        final Thread animThread = new Thread(() -> {
            int idx = 0;
            while (!Thread.currentThread().isInterrupted()) {
                idx %= frames.length;
                final ImageData frame = frames[idx];

                display.asyncExec(() -> {
                    if (canvas.isDisposed()) return;
                    Image frameImg = new Image(display, frame);
                    gc.drawImage(frameImg, frame.x, frame.y);
                    frameImg.dispose();
                    canvas.redraw();
                });

                try { Thread.sleep(frame.delayTime * 10); }
                catch (InterruptedException e) { return; }

                idx++;
            }
        });

        // 3. 視窗關閉清理
        shell.addShellListener(new ShellAdapter() {
            @Override public void shellClosed(ShellEvent e) { animThread.interrupt(); }
        });

        shell.setSize(400, 300);
        shell.open();
        animThread.start();

        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) display.sleep();
        }
        gc.dispose();
        canvasImage.dispose();
        display.dispose();
    }

    public static void main(String[] args) { new Animations(); }
}

進階補充:正確處理 Disposal Method

GIF 幀之間可能有「不處理、恢復背景、恢復上一幀」三種 disposal 方式。上例為簡化未處理,生產級播放器需根據 frame.disposalMethod 在繪製前清除畫布或還原前一幀,否則會出現殘影。

三、資源管理最佳實踐

資源建立處釋放處備註
Displaymain 開頭main 結尾 dispose()進程僅需一個
Image (靜態)載入後視窗關閉前未釋放會洩漏原生記憶體
Image (動畫幀)asyncExec 內繪製後立即 dispose()短命物件,必須即時釋放
GC建立目標 Image 後程式結束前綁定單一 Image
Thread啟動動畫前interrupt() + join()避免視窗關閉後執行緒殘留

四、結語

SWT 底層直通作業系統圖形子系統,雖 API 相對底層,但靈活度極高。掌握 ImageData 像素操作與 ImageLoader 多幀解碼,配合 asyncExec 跨執行緒 UI 更新,即可實現從簡單遮罩到複雜動畫的各類視覺特效。建議在真實專案中封裝 AnimatedImage、AlphaMaskFilter 等可復用元件,提升開發效率。

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