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

C++Builder 圖形程式設計:Image 元件實現「中心擴散」與「百葉窗」特效動畫完整教學

     編輯:關於C++

在 C++Builder 中利用 TImage 元件與 TCanvas 繪圖介面,無需複雜的 DirectX/OpenGL,即可輕鬆實現視覺效果優異的圖片進場動畫。本文詳細講解兩種經典特效——中心擴散與百葉窗簾的演算法邏輯、核心代碼實作與優化技巧。

核心元件與屬性準備

  • 放置一個 TImage (Image1),設定 Picture 載入 BMP/JPG/PNG 圖片。
  • 設定 Image1->AutoSize = true 或手動調整 Width/Height 與圖片原始尺寸一致。
  • 放置兩個 TButton:btnCenterSpread (Caption="中心擴散")、btnBlinds (Caption="百葉窗簾")。

特效一:中心擴散演算法解析

原理:從圖片幾何中心點開始,逐漸增加顯示矩形的寬高,直到覆蓋完整圖片區域。每一幀計算當前顯示矩形的 Left, Top, Width, Height,並呼叫 Refresh() 觸發重繪。

數學模型 (假設原始圖片寬 W、高 H、中心點 (Cx, Cy)):

  • 第 i 幀 (0 ≤ i ≤ W):顯示寬度 w = i,高度 h = i * H / W (保持長寬比)。
  • 左上角座標:Left = Cx - w/2, Top = Cy - h/2。

完整實作代碼 (btnCenterSpread.OnClick)

void __fastcall TForm1::btnCenterSpreadClick(TObject *Sender) {
    // 1. 記錄原始位置與尺寸
    int origLeft = Image1->Left;
    int origTop  = Image1->Top;
    int origW    = Image1->Width;
    int origH    = Image1->Height;

    // 2. 動畫幀迴圈 (以寬度為基準遞增)
    for (int i = 0; i <= origW; i += 2) { // 步進 2 像素加速,可依效能調整
        // 計算當前顯示矩形
        int curW = i;
        int curH = (curW * origH) / origW; // 整數運算保持比例

        // 計算左上角使其居中
        int curLeft = origLeft + (origW - curW) / 2;
        int curTop  = origTop  + (origH - curH) / 2;

        // 套用至 Image 元件 (觸發視覺更新)
        Image1->Left   = curLeft;
        Image1->Top    = curTop;
        Image1->Width  = curW;
        Image1->Height = curH;

        Image1->Refresh(); // 強制立即重繪
        Application->ProcessMessages(); // 處理訊息佇列,保持 UI 回應

        // 簡易幀率控制 (約 60 FPS = 16ms)
        Sleep(10); // 可改用高精度計時器
    }

    // 3. 確保最終狀態完全正確
    Image1->Left   = origLeft;
    Image1->Top    = origTop;
    Image1->Width  = origW;
    Image1->Height = origH;
    Image1->Refresh();
}

特效二:百葉窗簾演算法解析

原理:將圖片水平切割為 N 條等寬「葉片」。動畫過程中,逐行掃描:每一幀將每一片葉片的下一行像素從來源畫布複製到目標畫布。視覺上呈現「百葉窗由上而下逐漸打開」的效果。

關鍵技術:TCanvas::CopyRect() — 高效像素區塊複製 (GDI BitBlt 封裝)。

完整實作代碼 (btnBlinds.OnClick)

void __fastcall TForm1::btnBlindsClick(TObject *Sender) {
    // 1. 參數設定
    const int LEAF_COUNT = 16;          // 葉片數量 (可調整,越多越細膩)
    int imgW = Image1->Width;
    int imgH = Image1->Height;
    int leafH = imgH / LEAF_COUNT;      // 每葉片高度 (像素)

    // 2. 建立離屏位圖作為目標畫布 (避免螢幕閃爍)
    Graphics::TBitmap *pBmp = new Graphics::TBitmap();
    try {
        pBmp->Width  = imgW;
        pBmp->Height = imgH;
        pBmp->PixelFormat = pf24bit; // 或 pf32bit 提升複製效能

        // 3. 動畫主迴圈:逐行掃描 (總行數 = leafH)
        for (int scanLine = 0; scanLine < leafH; ++scanLine) {
            // 遍歷每一片葉片
            for (int leaf = 0; leaf < LEAF_COUNT; ++leaf) {
                int srcY = leaf * leafH + scanLine; // 來源 Y 座標
                int dstY = srcY;                    // 目標 Y 座標 (同位置)

                // 定義來源矩形 (來源圖片的單一掃描線)
                TRect srcRect(0, srcY, imgW, srcY + 1);
                // 定義目標矩形 (離屏位圖對應位置)
                TRect dstRect(0, dstY, imgW, dstY + 1);

                // 高效複製:來源 Image1.Canvas -> 目標 pBmp.Canvas
                pBmp->Canvas->CopyRect(dstRect, Image1->Canvas, srcRect);
            }

            // 4. 將離屏位圖一次性繪製到表單/容器畫布 (雙緩衝)
            // 假設 Image1 置於 Form1 上,直接繪製到 Form1 畫布
            // 實務上建議繪製到另一個 TImage 或 TPaintBox 的 Canvas
            Form1->Canvas->Draw(Image1->Left, Image1->Top, pBmp);

            Application->ProcessMessages();
            Sleep(5); // 控制動畫速度
        }
    }
    __finally {
        delete pBmp; // 釋放資源
    }

    // 動畫結束後,確保原始 Image1 可見 (若動畫期間將其 Visible=false)
    // Image1->Visible = true;
}

進階優化與擴展技巧

優化方向做法效果
消除閃爍1. 表單 DoubleBuffered = true (BCB6+)。
2. 使用離屏 TBitmap 雙緩衝 (如百葉窗範例)。
3. 覆寫 WM_ERASEBKGND 返回 1 禁止背景擦除。
動畫流暢無撕裂
幀率獨立使用 TTimer (Interval=16) 或多媒體計時器 (timeSetEvent) 驅動動畫狀態機,而非 Sleep 阻塞主執行緒。UI 保持回應,動畫速度穩定
加速複製TBitmap->PixelFormat = pf32bit (32位對齊) 配合 CopyRect 最快。大圖可考慮 StretchBlt / AlphaBlend (GDI+)。CPU 佔用降低
動畫曲線引入 緩動函數 (Easing: EaseOutQuad, EaseInOutCubic) 計算每幀進度,取代線性遞增。視覺更自然專業
方向變化修改掃描順序:垂直百葉 (水平切割)、對角線、圓形擴散、馬賽克、淡入淡出 (AlphaBlend)。豐富視覺效果庫

完整動畫狀態機架構範例 (非阻塞、可暫停/停止)

// 表單私有欄位
enum TAnimType { atNone, atCenterSpread, atBlinds };
TAnimType FAnimType = atNone;
int FAnimStep = 0, FAnimMaxStep = 0;
TBitmap *FOffscreenBmp = nullptr;
TTimer *FAnimTimer;

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {
    FAnimTimer = new TTimer(this);
    FAnimTimer->Interval = 16; // ~60 FPS
    FAnimTimer->OnTimer = AnimTimerTick;
    FAnimTimer->Enabled = false;
}

void __fastcall TForm1::StartAnimation(TAnimType type) {
    if (FAnimType != atNone) return; // 防止重入
    FAnimType = type;
    FAnimStep = 0;

    if (type == atCenterSpread) {
        FAnimMaxStep = Image1->Width / 2; // 步進 2px
    } else if (type == atBlinds) {
        const int LEAF_COUNT = 16;
        FAnimMaxStep = Image1->Height / LEAF_COUNT; // 掃描行數
        // 建立離屏位圖
        FOffscreenBmp = new TBitmap();
        FOffscreenBmp->Width = Image1->Width;
        FOffscreenBmp->Height = Image1->Height;
        FOffscreenBmp->PixelFormat = pf32bit;
    }
    FAnimTimer->Enabled = true;
}

void __fastcall TForm1::AnimTimerTick(TObject *Sender) {
    if (FAnimType == atCenterSpread) {
        // ... 執行中心擴散單步 (同前代碼,但無 for 迴圈,僅單步 FAnimStep++)
        if (FAnimStep >= FAnimMaxStep) StopAnimation();
    } else if (FAnimType == atBlinds) {
        // ... 執行百葉窗單步掃描 (同前代碼,單步 FAnimStep++)
        if (FAnimStep >= FAnimMaxStep) StopAnimation();
    }
    FAnimStep++;
}

void __fastcall TForm1::StopAnimation() {
    FAnimTimer->Enabled = false;
    if (FOffscreenBmp) { delete FOffscreenBmp; FOffscreenBmp = nullptr; }
    FAnimType = atNone;
    // 還原 Image1 顯示
    Image1->Refresh();
}

// 按鈕事件
void __fastcall TForm1::btnCenterSpreadClick(TObject *Sender) { StartAnimation(atCenterSpread); }
void __fastcall TForm1::btnBlindsClick(TObject *Sender) { StartAnimation(atBlinds); }

總結

善用 TImage 幾何屬性控制 (Left/Top/Width/Height) 實現幾何變換動畫,配合 TCanvas::CopyRect 像素級操作實現紋理掃描動畫,是 C++Builder VCL 圖形程式設計的兩大核心技法。掌握離屏雙緩衝、計時器驅動狀態機、緩動函數等進階模式,即可構建專業級的 UI 動畫效果,大幅提升應用程式的使用者體驗。

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