Direct2D 实现窗口透明

发布时间 2023-08-07 16:13:55作者: Dir-A

不需要设置多余的WS_EX_XXX样式,主要就两步

第一步是开启DWM的Alpha透明混合,也就是创建窗口后,调用EnableAlphaCompositing这个函数,这个函数是glfw里面的,具体可以去看做了什么。

第二步要配置Direct2D RenderTarget的props,也就是设置 D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED) 成支持Alpha混合模式

这样就可以设置Direct2D的alpha值来控制窗口的透明度了,窗口边框之类的,自行修改样式解决。

  1 #include <d2d1.h>
  2 #include <dwmapi.h>
  3 #include <versionhelpers.h>
  4 #pragma comment(lib, "dwmapi")
  5 #pragma comment(lib, "d2d1.lib")
  6 
  7 
  8 static ID2D1Factory* sg_pID2D1Factory = nullptr;
  9 static ID2D1HwndRenderTarget* sg_pRenderTarget = nullptr;
 10 
 11 
 12 // https://github.com/glfw/glfw/blob/master/src/win32_window.c#L368C27-L368C27
 13 bool EnableAlphaCompositing(HWND hWnd)
 14 {
 15     if (!::IsWindowsVistaOrGreater()) { return false; }
 16 
 17     BOOL is_composition_enable = false;
 18     ::DwmIsCompositionEnabled(&is_composition_enable);
 19     if (!is_composition_enable) { return true; }
 20 
 21     DWORD current_color = 0;
 22     BOOL is_opaque = false;
 23     ::DwmGetColorizationColor(&current_color, &is_opaque);
 24 
 25     if (!is_opaque || IsWindows8OrGreater())
 26     {
 27         HRGN region = ::CreateRectRgn(0, 0, -1, -1);
 28         DWM_BLURBEHIND bb = { 0 };
 29         bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
 30         bb.hRgnBlur = region;
 31         bb.fEnable = TRUE;
 32         ::DwmEnableBlurBehindWindow(hWnd, &bb);
 33         ::DeleteObject(region);
 34         return true;
 35     }
 36     else // For Window7
 37     {
 38         DWM_BLURBEHIND bb = { 0 };
 39         bb.dwFlags = DWM_BB_ENABLE;
 40         ::DwmEnableBlurBehindWindow(hWnd, &bb);
 41         return false;
 42     }
 43 }
 44 
 45 
 46 LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 47 {
 48     if (uMsg == WM_PAINT)
 49     {
 50         sg_pRenderTarget->BeginDraw();
 51         sg_pRenderTarget->Clear(D2D1::ColorF(0.2f, 0.3f, 0.5f, 0.5f));
 52         sg_pRenderTarget->EndDraw();
 53     }
 54 
 55     return DefWindowProcW(hWnd, uMsg, wParam, lParam);
 56 }
 57 
 58 
 59 int main()
 60 {
 61     // 窗口类定义
 62     WNDCLASSEXW wcx = { 0 };
 63     wcx.cbSize = sizeof(wcx);
 64     wcx.lpfnWndProc = WindowProc;
 65     wcx.lpszClassName = L"Test Class";
 66     wcx.hInstance = GetModuleHandleW(nullptr);
 67 
 68     // 注册窗口类
 69     ::RegisterClassExW(&wcx);
 70 
 71     //创建窗口
 72     HWND hwnd = ::CreateWindowExW
 73     (
 74         NULL, wcx.lpszClassName, L"Main Window", WS_OVERLAPPEDWINDOW, 
 75         CW_USEDEFAULT, CW_USEDEFAULT, 1280, 720, 
 76         nullptr, nullptr, wcx.hInstance, nullptr
 77     );
 78 
 79     // 开启Alpha通道混合
 80     EnableAlphaCompositing(hwnd);
 81 
 82     // 创建Direct2D资源
 83     {
 84         D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &sg_pID2D1Factory);
 85 
 86         RECT rc = { 0 };
 87         GetClientRect(hwnd, &rc);
 88         D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
 89 
 90         D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties
 91         (
 92             D2D1_RENDER_TARGET_TYPE_DEFAULT,
 93             D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)
 94         );
 95         sg_pID2D1Factory->CreateHwndRenderTarget(props, D2D1::HwndRenderTargetProperties(hwnd, size), &sg_pRenderTarget);
 96     }
 97 
 98     // 显示窗口
 99     ShowWindow(hwnd, SW_NORMAL);
100 
101     // 消息循环
102     MSG msg = { 0 };
103     while (GetMessageW(&msg, nullptr, 0, 0))
104     {
105         ::TranslateMessage(&msg);
106         ::DispatchMessageW(&msg);
107     }
108 
109     // 清理Direct2D资源
110     sg_pRenderTarget->Release();
111     sg_pID2D1Factory->Release();
112 
113     // 注销窗口类
114     UnregisterClassW(wcx.lpszClassName, wcx.hInstance);
115 }