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

VC++ 漸變色背景繪製:OnDraw 像素級填充與滑鼠互動切換

     編輯:VC 教學

前言

想給單文檔/對話框加個好看的漸變背景?**不需要調色板、不需要 DIB、不需要 GDI+**,純 GDI `FillSolidRect` + 迴圈幾行代碼即可實現平滑漸變,並支援滑鼠點擊隨機換色。本文以單文檔視圖為例完整演示。

核心原理:水平掃描線逐像素填充

將客戶區寬度 `nWidth` 分成 `nWidth` 條 1 像素寬的垂直矩形,每條根據 X 座標計算 RGB 分量,形成線性漸變。

完整實作代碼

1. 視圖類成員變數 (ShadowView.h)


class CShadowView : public CView {
    int m_nColorR, m_nColorG; // 藍色固定 255,紅/綠動態
    // ...
};

2. 建構函式初始化 (ShadowView.cpp)


CShadowView::CShadowView() : m_nColorR(255), m_nColorG(255) {}

3. OnDraw 核心漸變邏輯


void CShadowView::OnDraw(CDC* pDC) {
    CShadowDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);

    CRect rcClient;
    GetClientRect(&rcClient);
    int nWidth = rcClient.Width();
    int nHeight = rcClient.Height();

    CRect rectBand;
    for (int x = 0; x < nWidth; ++x) {
        rectBand.SetRect(x, 0, x + 1, nHeight); // 1px 寬垂直帶
        // 紅、綠固定,藍從 255 線性遞減到 0
        BYTE bBlue = (BYTE)(255 - MulDiv(x, 255, nWidth));
        COLORREF cr = RGB(m_nColorR, m_nColorG, bBlue);
        pDC->FillSolidRect(&rectBand, cr);
    }
}

4. 滑鼠左鍵隨機換色


void CShadowView::OnLButtonDown(UINT nFlags, CPoint point) {
    // 產生 0~255 隨機數
    auto randByte = []() -> BYTE {
        return (BYTE)((rand() * 255.0) / RAND_MAX + 0.5);
    };
    m_nColorR = randByte();
    m_nColorG = randByte();

    Invalidate(TRUE); // 觸發 WM_PAINT → OnDraw 重繪
    CView::OnLButtonDown(nFlags, point);
}

效果展示

  • 啟動:黃色系漸變 (R=255, G=255, B=255→0)
  • 點擊任意處:隨機 R/G,藍色漸變保持,呈現不同色調漸變
  • 調整視窗大小:`OnDraw` 即時重算,無拉伸失真

進階變體:多種漸變方向與模式

模式核心修改代碼片段
垂直漸變 (上→下)外層迴圈 `y`,`MulDiv(y, 255, nHeight)``rectBand.SetRect(0, y, nWidth, y+1);`
對角線漸變`MulDiv(x+y, 255, nWidth+nHeight)`單一雙層迴圈或預計算查表
雙色線性插值起始色 `c1`、結束色 `c2`,`LERP(c1, c2, t)``BYTE r = c1.R + (c2.R - c1.R) * x / nWidth;`
多色段漸變定義色標陣列 `stops[]`,區間內插值參考 GDI+ `ColorBlend` 邏輯
徑向漸變 (圓心擴散)計算到中心距離 `dist`,`t = dist / maxRadius`需雙層迴圈,效能較低

效能優化:從像素級到區塊級

逐像素 `FillSolidRect` 在 4K 視窗 (3840×2160) 需 3840 次 GDI 呼叫,略慢。優化方案:

  1. 區塊合併:相同顏色連續像素合併為寬矩形一次填充
  2. 離屏位圖:`CreateCompatibleBitmap` → 離屏繪製 → `BitBlt` 一次上螢幕 (雙緩衝)
  3. GDI+ `LinearGradientBrush`:硬體加速、代碼更簡潔 (需 `gdiplus.lib`)
  4. Direct2D:現代 GPU 渲染管線,效能最強

離屏位圖優化範例 (雙緩衝無閃爍)


void CShadowView::OnDraw(CDC* pDC) {
    CRect rc; GetClientRect(&rc);
    CDC memDC; memDC.CreateCompatibleDC(pDC);
    CBitmap bmp; bmp.CreateCompatibleBitmap(pDC, rc.Width(), rc.Height());
    CBitmap* pOld = memDC.SelectObject(&bmp);

    // 在 memDC 繪製漸變 (同前邏輯)
    for (int x = 0; x < rc.Width(); ++x) {
        CRect band(x, 0, x+1, rc.Height());
        BYTE b = 255 - MulDiv(x, 255, rc.Width());
        memDC.FillSolidRect(&band, RGB(m_nColorR, m_nColorG, b));
    }

    pDC->BitBlt(0, 0, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY);
    memDC.SelectObject(pOld);
}

結語

**GDI 像素級填充** 是理解漸變本質的最佳入門:**顏色空間線性插值 + 掃描線光柵化**。雖然生產環境建議用 GDI+/Direct2D,但這段「純 GDI、無依賴、幾十行」的代碼,在嵌入式、舊系統維護、輕量級工具中極具價值。掌握 `MulDiv`、`FillSolidRect`、`Invalidate` 三板斧,漸變、波紋、掃描光、甚至簡易光線投射,信手拈來。

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