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

VC++ 實現視窗透明效果:SetLayeredWindowAttributes 動態載入技巧

     編輯:VC 教學

背景與挑戰

Windows 2000+ 引入 WS_EX_LAYERED 擴充樣式與 SetLayeredWindowAttributes API,可輕鬆實現視窗整體透明或色鍵透明。但舊版 VC6 SDK 未包含此 API 宣告,導致編譯錯誤「未定義識別項」。

解決方案:執行期動態載入

視作「未公開 API」,透過 LoadLibrary + GetProcAddress 取得函數指標呼叫。

關鍵常數 (SDK 未定義時自行補充)

#define WS_EX_LAYERED 0x00080000
#define LWA_COLORKEY 0x00000001
#define LWA_ALPHA    0x00000002

完整實作代碼 (對話框 OnInitDialog)

BOOL CMyDialog::OnInitDialog()
{
    CDialog::OnInitDialog();

    // 1. 加入 WS_EX_LAYERED 擴充樣式
    LONG exStyle = GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE);
    SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, exStyle | WS_EX_LAYERED);

    // 2. 動態載入 user32.dll 並取得函數指標
    HINSTANCE hUser32 = LoadLibrary(_T("User32.dll"));
    if (hUser32)
    {
        typedef BOOL (WINAPI *PFN_SetLayeredWindowAttributes)(
            HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags);

        PFN_SetLayeredWindowAttributes pFunc =
            (PFN_SetLayeredWindowAttributes)GetProcAddress(hUser32,
                "SetLayeredWindowAttributes");

        if (pFunc)
        {
            // 參數說明:
            // hwnd: 目標視窗
            // crKey: 色鍵顏色 (dwFlags 包含 LWA_COLORKEY 時生效)
            // bAlpha: 透明度 0(全透明)~255(不透明) (dwFlags 包含 LWA_ALPHA 時生效)
            // dwFlags: LWA_ALPHA | LWA_COLORKEY
            //
            // 範例:整體 50% 透明 (Alpha=128)
            pFunc(GetSafeHwnd(), 0, 128, LWA_ALPHA);

            // 範例:指定白色 (RGB(255,255,255)) 為透明色
            // pFunc(GetSafeHwnd(), RGB(255,255,255), 0, LWA_COLORKEY);
        }
        FreeLibrary(hUser32);
    }

    return TRUE;
}

參數組合效果對照

dwFlagscrKeybAlpha效果
LWA_ALPHA忽略0~255整體透明度,0=隱形, 255=實體
LWA_COLORKEYRGB 色值忽略指定顏色像素全透明,其餘不透明
LWA_ALPHA | LWA_COLORKEYRGB 色值0~255先色鍵透明,再整體 Alpha 混合

進階應用:淡入/淡出動畫

void CMyDialog::FadeIn(int durationMs = 500)
{
    SetTimer(1, 20, NULL);  // 20ms 間隔
    m_fadeStart = GetTickCount();
    m_fadeDuration = durationMs;
    m_fadingIn = TRUE;
}

void CMyDialog::OnTimer(UINT_PTR nIDEvent)
{
    if (nIDEvent == 1)
    {
        DWORD elapsed = GetTickCount() - m_fadeStart;
        if (elapsed >= m_fadeDuration)
        {
            KillTimer(1);
            BYTE finalAlpha = m_fadingIn ? 255 : 0;
            SetLayeredAlpha(finalAlpha);
            return;
        }

        BYTE alpha = (BYTE)(255.0 * elapsed / m_fadeDuration);
        if (!m_fadingIn) alpha = 255 - alpha;
        SetLayeredAlpha(alpha);
    }
    CDialog::OnTimer(nIDEvent);
}

void CMyDialog::SetLayeredAlpha(BYTE alpha)
{
    HINSTANCE h = LoadLibrary(_T("User32.dll"));
    if (h)
    {
        auto pFunc = (BOOL(WINAPI*)(HWND,COLORREF,BYTE,DWORD))
            GetProcAddress(h, "SetLayeredWindowAttributes");
        if (pFunc) pFunc(GetSafeHwnd(), 0, alpha, LWA_ALPHA);
        FreeLibrary(h);
    }
}

注意事項

  • 最低系統需求:Windows 2000 / XP / Server 2003 / Vista / 7 / 10 / 11。Win9x/Me 不支援。
  • Alpha=0 視窗完全透明且不可點擊,使用者找不到視窗關閉,請保留最小可見度 (如 10~20)。
  • 子控制項:整體 Alpha 會影響所有子控制項;若需子控制項不透明,需改用 UpdateLayeredWindow 繪製自訂介面。
  • 效能:分層視窗由 DWM (Desktop Window Manager) 合成,現代硬體幾乎零負擔。
  • 升級 SDK:安裝 Windows SDK 7.1+ 即可直接 #include <windows.h> 使用,無需動態載入。

動態載入 SetLayeredWindowAttributes 讓舊版 VC6 專案也能輕鬆擁有現代透明視窗效果,配合計時器即可實現優雅的淡入淡出動畫。

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