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

透明位圖視窗類:以指定顏色為透明色,打造不規則形狀 UI

     編輯:關於VC++

Windows 預設視窗為矩形,若要做出圓形、動漫角色造型、邊緣羽化等不規則介面,最經典做法是區域視窗 (Window Region):載入位圖、掃描像素、以透明色建立 HRGN、SetWindowRgn。本文封裝一個 CTransparentWnd 類別,三行程式碼即可將任意位圖變成可點擊、可拖曳、可疊加的不規則視窗。

核心原理

  1. 準備一張位圖,指定一個極少使用的顏色作為透明色 (建議 RGB(255,0,255) 洋紅)。
  2. WM_CREATE 時:
    ① 建立相容 DC 載入位圖。
    ② 雙重迴圈掃描每個像素 GetPixel(x,y)。
    ③ 非透明色像素建立 1x1 矩形區域 CreateRectRgn,CombineRgn(RGN_OR) 合併。
    ④ SetWindowRgn 套用至視窗。
  3. WM_ERASEBKGND:StretchBlt 繪製位圖填滿客戶區。
  4. 對外提供 SetPic(UINT nID, int x, int y):載入資源位圖、計算大小、Create 視窗、ShowWindow。

完整類別實作


// TransparentWnd.h
#pragma once
class CTransparentWnd : public CWnd {
    DECLARE_DYNAMIC(CTransparentWnd)
    CRect m_rcWnd; CBitmap m_bmp; BITMAP m_bm;
    static constexpr COLORREF TRANS_COLOR = RGB(255,0,255);
public:
    CTransparentWnd(); virtual ~CTransparentWnd();
    void SetPic(UINT nIDPic, int nLeft, int nTop); // 外部呼叫入口
protected:
    afx_msg int OnCreate(LPCREATESTRUCT lpCS);
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    DECLARE_MESSAGE_MAP()
};

// TransparentWnd.cpp
#include "stdafx.h"
#include "TransparentWnd.h"
IMPLEMENT_DYNAMIC(CTransparentWnd, CWnd)
BEGIN_MESSAGE_MAP(CTransparentWnd, CWnd)
    ON_WM_CREATE()
    ON_WM_ERASEBKGND()
END_MESSAGE_MAP()

CTransparentWnd::CTransparentWnd() {}
CTransparentWnd::~CTransparentWnd() {}

int CTransparentWnd::OnCreate(LPCREATESTRUCT lpCS) {
    if (CWnd::OnCreate(lpCS) == -1) return -1;
    GetWindowRect(&m_rcWnd);
    CRgn wndRgn, rgnPixel;
    wndRgn.CreateRectRgn(0, 0, m_rcWnd.Width(), m_rcWnd.Height());
    CDC* pDC = GetWindowDC(); CDC dcMem; dcMem.CreateCompatibleDC(pDC);
    CBitmap* pOld = dcMem.SelectObject(&m_bmp);
    for (int x = 0; x < m_rcWnd.Width(); ++x) {
        for (int y = 0; y < m_rcWnd.Height(); ++y) {
            if (dcMem.GetPixel(x, y) == TRANS_COLOR) {
                rgnPixel.CreateRectRgn(x, y, x+1, y+1);
                wndRgn.CombineRgn(&wndRgn, &rgnPixel, RGN_XOR); // 排除透明像素
                rgnPixel.DeleteObject();
            }
        }
    }
    SetWindowRgn((HRGN)wndRgn, TRUE);
    dcMem.SelectObject(pOld); ReleaseDC(pDC); ReleaseDC(&dcMem);
    return 0;
}

BOOL CTransparentWnd::OnEraseBkgnd(CDC* pDC) {
    CDC dcMem; dcMem.CreateCompatibleDC(pDC);
    CBitmap* pOld = dcMem.SelectObject(&m_bmp);
    pDC->StretchBlt(0, 0, m_bm.bmWidth, m_bm.bmHeight, &dcMem, 0, 0, m_bm.bmWidth, m_bm.bmHeight, SRCCOPY);
    dcMem.SelectObject(pOld); ReleaseDC(&dcMem);
    return TRUE;
}

void CTransparentWnd::SetPic(UINT nIDPic, int nLeft, int nTop) {
    if (m_bmp.m_hObject) m_bmp.DeleteObject();
    m_bmp.LoadBitmap(nIDPic); m_bmp.GetBitmap(&m_bm);
    CRect rc(nLeft, nTop, nLeft + m_bm.bmWidth, nTop + m_bm.bmHeight);
    Create(nullptr, nullptr, WS_CHILD | WS_VISIBLE, rc, AfxGetApp()->m_pMainWnd, nIDPic);
    ShowWindow(SW_SHOWNORMAL);
}

使用範例


// 主對話框頭檔
class CMainDlg : public CDialogEx {
    CTransparentWnd m_wndSkin; // 成員變數
    // ...
};

// OnInitDialog
BOOL CMainDlg::OnInitDialog() {
    CDialogEx::OnInitDialog();
    m_wndSkin.SetPic(IDB_BITMAP_IRREGULAR, 10, 10); // 資源 ID、左上角座標
    return TRUE;
}

效果展示

來源位圖:洋紅為透明色 執行效果:不規則視窗 疊加多個透明視窗

效能優化建議

問題優化方案
雙重迴圈 GetPixel 極慢 (O(n²))① LockBits (GDI+) / GetDIBits 一次讀全圖像素陣列 → 記憶體掃描。
② 僅掃描邊緣 (Marching Squares) 產生多邊形區域。
③ 離線預計算區域資料嵌入資源,執行期直接 CreatePolygonRgn。
高 DPI 模糊位圖內建多解析度版本 (IDB_BITMAP_100, _125, _150),依 GetDpiForWindow 載入對應資源。
動畫/影片透明需逐幀切換區域 → 改用 Layered Window (WS_EX_LAYERED + UpdateLayeredWindow + 32-bit Alpha 通道 PNG),支援半透明、淡入淡出、GPU 加速。
點擊穿透Layered Window 可設 LWA_ALPHA + HitTest 區域,或 WM_NCHITTEST 回傳 HTTRANSPARENT 實現點擊穿透。

現代替代方案對比

方案優點缺點適用場景
本文區域視窗 (GDI)相容 XP+、無額外依賴、邏輯簡單無半透明、建立區域慢、高 DPI 模糊簡易工具、啟動畫面、不規則按鈕
Layered Window (WS_EX_LAYERED)支援 Alpha、GPU 加速、可點擊穿透Win2K+、需 32-bit DIB、GDI 繪圖較繁瑣半透明視窗、OSD、拖曳預覽
DWM 縮圖/即時預覽系統級合成、效能最佳Vista+、API 複雜任務列縮圖、Aero Peek
DirectComposition / WinUI 3現代圖形管線、動畫豐富、XAML 整合Win10 1809+、學習曲線陡新專案、複雜 UI、高效能動畫

CTransparentWnd 以 50 行核心程式碼實現經典不規則視窗,適合快速原型與舊專案維護。新專案建議直接採用 Layered Window + PNG Alpha 或 WinUI 3 獲得完整半透明與動畫支援。完整專案 (含優化版 LockBits 掃描、多解析度資源、拖曳移動、右鍵選單) 請參考文章附件。

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