在Windows11中常见的有:Acrylic(亚克力)、Mica(云母)、MicaAlt(特殊云母)
使用DWMAPI:dwmapi库来应用,理论支持任意Windows窗口,不仅限于C/C++
使用WindowsAPI(C++)为任意Windows窗口应用特殊背景样式
使用dwmapi
在C++中,使用Windows中头文件<dwmapi.h>
在Windows GUI程序开发中都可以间接、直接的使用C++接口
理论上,任意Windows窗口都可以实现效果,不限语言
基本:两个函数、两个枚举
先直接上代码,非常简单,后面是细讲
//HWND hwnd :变量 已获取的目标窗口句柄
constexpr auto type = DWM_SYSTEMBACKDROP_TYPE::DWMSBT_MAINWINDOW;
constexpr auto margins = MARGINS{-1, -1, -1, -1};
DwmExtendFrameIntoClientArea(hwnd, &margins);
DwmSetWindowAttribute(
hwnd,
DWMWINDOWATTRIBUTE::DWMWA_SYSTEMBACKDROP_TYPE,
&type,
sizeof(type));
hwnd Windows窗口句柄,在原生WindowsGUI开发中,可以直接使用,若使用框架
Qt中
:使用WId QWidget::winId() const
获取,转换 HWND hwnd = reinterpret_cast<HWND>(widget->winId())
wxWidgets
中:使用virtual WXWidget wxWindow::GetHandle () const
获取,转换 HWND hwnd = static_cast<HWND>(window->GetHandle())
其他框架应该都有类似的接口
Bilibili视频 讲解|演示:https://www.bilibili.com/video/BV185FLeUESf
应用/实战
使用函数前,Windows可能并不会自动加载DWM库,需要手动加载
使用
MSVC
编译器时 可以设置以下的预处理指令#pragma comment(lib, "dwmapi.lib")
使用
MinGW(gcc/g++)
或MSVC
编译器时 可以动态加载库(通用)HMODULE dwmapi = LoadLibrary(L"dwmapi.dll");
定义函数指针类型typedef HRESULT (WINAPI *pFN)(HWND, const MARGINS*);
获取函数指针const auto DwmExtendFrameIntoClientArea = (pFN)(pfn_ExtendFrameIntoClientArea);
//在头文件中 xxx.h
#include <windows.h>
#ifdef _MSC_VER
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
#else
constexpr auto DWMWA_SYSTEMBACKDROP_TYPE = 38;
typedef enum DWM_SYSTEMBACKDROP_TYPE {
DWMSBT_AUTO,
DWMSBT_NONE,
DWMSBT_MAINWINDOW,
DWMSBT_TRANSIENTWINDOW,
DWMSBT_TABBEDWINDOW
};
typedef HRESULT (WINAPI *pExtendFrameIntoClientArea)(HWND, const MARGINS*);
typedef HRESULT (WINAPI *pSetWindowAttribute)(HWND, DWORD, LPCVOID, DWORD);
const extern pExtendFrameIntoClientArea DwmExtendFrameIntoClientArea;
const extern pSetWindowAttribute DwmSetWindowAttribute;
#endif
//在源文件中 xxx.cpp
#ifndef _MSC_VER
HMODULE dwmapi = LoadLibrary(L"dwmapi.dll");
const auto pfn_ExtendFrameIntoClientArea = GetProcAddress(dwmapi, "DwmExtendFrameIntoClientArea")
const auto pfn_SetWindowAttribute = GetProcAddress(dwmapi, "DwmSetWindowAttribute");
const auto DwmExtendFrameIntoClientArea = reinterpret_cast<pExtendFrameIntoClientArea>(pfn_ExtendFrameIntoClientArea);
const auto DwmSetWindowAttribute = reinterpret_cast<pSetWindowAttribute>(pfn_SetWindowAttribute);
#endif
/* 最后可封装为以下函数 */
/// @brief 设置窗口样式
/// @param hwnd Windows窗口句柄
/// @param type 样式 从枚举DWM_SYSTEMBACKDROP_TYPE中选择
void SetWindowStyle(HWND hwnd, DWM_SYSTEMBACKDROP_TYPE type)
{
constexpr auto margins = MARGINS{-1, -1, -1, -1}; //若值其中某一值为负数,则会扩展到整个窗口,正好满足需求
auto style = GetWindowLong(hwnd, GWL_STYLE);
style |= WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CAPTION; //此处样式可以根据具体需求变换
SetWindowLong(hwnd, GWL_STYLE, style);
DwmExtendFrameIntoClientArea(hwnd, &margins);
DwmSetWindowAttribute(hwnd, DWMWA_SYSTEMBACKDROP_TYPE, &type, sizeof(type));
}
对于样式样式枚举 DWM_SYSTEMBACKDROP_TYPE
(仅为Windows11对应样式)
DWMSBT_AUTO = 0
自动:由系统决定背景样式,默认不设置即为该值DWMSBT_NONE = 1
无:无背景样式,通常为白色背景或是对应主题色DWMSBT_MAINWINDOW = 2 主窗口
云母(mica):云母样式DWMSBT_TRANSIENTWINDOW = 3 暂时窗口(如对话框)
亚克力(Acrylic):亚克力,Windows10中主要样式DWMSBT_TABBEDWINDOW = 4 选项卡窗口
特殊云母(MicaAlt):特殊云母样式可能会随着Windwos版本更新而改变
注意事项:
若使用GUI框架需要进行对应操作,诸如Qt,窗口有默认颜色,需要将窗口背景色设为透明
使用非C/C++时,可以将上述函数封装为库,如Java:JNI,即可实现Java窗口背景样式设置
有时候加载可能失效建议加上获取值检查,如函数指针是否为空,获取到的module是否是
以上样式通常为Windows11,windows10并不能很好的支持,Windows10中只对亚克力(Acrylic)有完整支持
调用函数时,可以取两个函数的返回值
类型:HRESULT
确认是否成功
总结
内容还是非常简单的,基本就两个函数,其他的就是版本还有编译器之类的问题了,最后注意参数等等即可。
参考文档
(微软官方文档) 函数 其一 边框扩展 DwmExtendFrameIntoClientArea 函数
(微软官方文档) 函数 其二 属性设置 DwmSetWindowAttribute 函数
(微软官方文档) 枚举 其一 窗口属性 DWMWINDOWATTRIBUTE
(微软官方文档) 枚举 其二 背景类型 DWM_SYSTEMBACKDROP_TYPE
(哔哩哔哩视频) 我的视频:https://www.bilibili.com/video/BV185FLeUESf