分类
标签
.NET 9008 adb android apt asp.net ASP.NET Core audio bug C c++ C++ chrome cmd csharp CSharp css css3 debian debug dotnet dotnet Framework dpkg GDI&GDI+ gdi&gdi+ golang graphics html html5 http java javascript json kali linux linux mci microsoft minimap MSBuild mysql OpenCV PInvoke powershell python QQ rust shell speex sql tutorial ubuntu ui unity vb.net visual studio Visual Studio web Web win32 winapi windows winform WinForm wpf WPF xaml xfce 列表 刷机 前端 加密 反射 反编译 可视化 图像处理 多线程 字符串 安卓 实例 局域网 幻影坦克 库 开发语言 异步 微信 手册 手机 接口 摘要 救砖 数字签名 数字证书 数字音频 数据库 桌面程序 游戏 游戏引擎 源码 爬虫 玩游戏 电脑硬件 笔记 算法 类库 线性代数 编程语言 网络 脚本语言 计算机图形学 计算机基础 设计模式 语音编解码 运维 进制 面向对象编程 音频 音频编码解码
739 字
4 分钟
[Win32] 窗体暗色模式, C++, WinForm, WPF 使用方法, 判断颜色模式, 响应颜色变更消息, 设置标题栏暗色.
2023 年了, 如果咱写的程序还不支持暗色模式, 那就说不过去了.
判断是否是暗色模式
在 Windows 中判断当前系统的颜色模式是否是暗色, 可以通过查询注册表项来实现.
下面是 C++ 的示例代码:
HKEY hKey;
const wchar_t* subKey = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
const wchar_t* valueName = L"AppsUseLightTheme";
DWORD value = -1;
DWORD valueSize = sizeof(DWORD);
if (RegOpenKeyEx(HKEY_CURRENT_USER, subKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
HRESULT hr = RegGetValue(hKey, nullptr, valueName, RRF_RT_REG_DWORD, nullptr, &value, &valueSize);
if (hr != S_OK)
{
value = -1; // 不要假定该键必须存在,如果找不到将返回默认值
}
RegCloseKey(hKey);
}
if (value == 0)
{
// 当前使用暗色主题
}
else if (value == 1)
{
// 当前使用亮色主题
}
else
{
// 无法确定当前主题
}
下面是 C# 示例代码:
using Microsoft.Win32;
RegistryKey key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize");
if (key != null)
{
int appsUseLightTheme = (int)key.GetValue("AppsUseLightTheme", -1);
if (appsUseLightTheme == 0)
{
// 当前使用暗色主题
}
else if (appsUseLightTheme == 1)
{
// 当前使用亮色主题
}
else
{
// 无法确定当前主题
}
key.Close();
}
设置窗口暗色模式
Windows 中自带了一个暗色模式的 WinAPI, 直接调用就可以将窗口标题栏变成暗色.
下面是 C++ 的示例代码:
#include <windows.h>
#include <dwmapi.h>
int main() {
HWND hWnd = GetMainWindowHandle(); // 获取主窗口句柄
DWORD dwAttribute = DWMWA_USE_IMMERSIVE_DARK_MODE; // 设置暗色模式属性
BOOL bValue = TRUE; // 启用暗色模式
DwmSetWindowAttribute(hWnd, dwAttribute, &bValue, sizeof(bValue)); // 设置窗口属性
return 0;
}
下面是 C# 的示例代码:
[DllImport("dwmapi.dll", PreserveSig = true)]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, DwmWindowAttribute attr, ref int attrValue, int attrSize);
public static bool EnableDarkModeForWindow(IntPtr hWnd, bool enable)
{
int darkMode = enable ? 1 : 0;
int hr = DwmSetWindowAttribute(hWnd, DwmWindowAttribute.UseImmersiveDarkMode, ref darkMode, sizeof(int));
return hr >= 0;
}
public enum DwmWindowAttribute : uint
{
NCRenderingEnabled = 1,
NCRenderingPolicy,
TransitionsForceDisabled,
AllowNCPaint,
CaptionButtonBounds,
NonClientRtlLayout,
ForceIconicRepresentation,
Flip3DPolicy,
ExtendedFrameBounds,
HasIconicBitmap,
DisallowPeek,
ExcludedFromPeek,
Cloak,
Cloaked,
FreezeRepresentation,
PassiveUpdateMode,
UseHostBackdropBrush,
UseImmersiveDarkMode = 20,
WindowCornerPreference = 33,
BorderColor,
CaptionColor,
TextColor,
VisibleFrameBorderThickness,
SystemBackdropType,
Last
}
响应配色更改
当系统配色更改的时候, 会向所有窗体发送一个 THEMECHANGED
消息:
C++ 中, 你可以在 WndProc 捕捉这个消息, 然后进行具体操作. 例如上面提到的, 设置窗口暗色模式.
#include <Windows.h>
#include <iostream>
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int main() {
// 注册窗口类
WNDCLASS wc = {};
wc.lpfnWndProc = WndProc;
wc.hInstance = GetModuleHandle(NULL);
wc.lpszClassName = L"MyWindowClass";
if (!RegisterClass(&wc)) {
std::cerr << "Failed to register window class" << std::endl;
return 1;
}
// 创建窗口
HWND hwnd = CreateWindow(
L"MyWindowClass",
L"My Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, GetModuleHandle(NULL), NULL
);
if (!hwnd) {
std::cerr << "Failed to create window" << std::endl;
return 1;
}
// 显示窗口
ShowWindow(hwnd, SW_SHOWDEFAULT);
// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_THEMECHANGED:
std::cout << "Theme changed" << std::endl;
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
C# 的话, 如果你在使用 WinForm 或 WPF, 你可以直接使用 C# 封装好的 SystemEvents
类, 它有一个 UserPreferenceChanged
事件, 通过订阅这个事件, 并判断具体分类, 最后执行操作:
SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;
private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
{
if (e.Category == UserPreferenceCategory.General)
{
// 更新颜色主题
}
}
[Win32] 窗体暗色模式, C++, WinForm, WPF 使用方法, 判断颜色模式, 响应颜色变更消息, 设置标题栏暗色.
https://slimenull.com/posts/20230404173208/