使用Qt 6.5的Windows 11上的黑暗模式

Dark Mode on Windows 11 with Qt 6.5

使用Qt 6.5的Windows 11上的黑暗模式

February 24, 2023 by Volker Hilsheimer | Comments

2023年2月24日Volker Hilsheimer |评论

With recent Windows 10 builds, and with Windows 11 even more so, dark color schemes have at last landed as a mainstream personalisation option on the Windows desktop. Qt has supported the dark appearance setting on macOS for many years, and with Qt 6.5 we are bringing better support for dark themes to Windows as well.

随着最近的Windows 10版本,以及Windows 11版本,深色方案终于成为Windows桌面上的主流个性化选项。Qt多年来一直支持macOS上的深色外观设置,通过Qt 6.5,我们也为Windows带来了对深色主题的更好支持。

QStyle in Windows XP

Windows XP上的QStyle

On Windows, theming and personalisation have a long history. Windows 3.1 already had custom mouse cursor and icon packages, and I filled several floppies and later DVDs with background images and sound effects inspired by the latest movies.

在Windows上,主题化和个性化由来已久。Windows3.1已经有了自定义的鼠标光标和图标包,我用最新电影的背景图像和音效填充了几张软盘和后来的DVD。

Proper UI theming was introduced with Windows XP through the Win32 APIs from the UxTheme system library. I went to the Microsoft's TechEd conference in Barcelona in 2001 to learn what we can expect from that framework over time. The possibilities seemed both endless and scary for people in the audience that had developed custom controls with MFC or Win32 APIs. I remember talks about round UI elements, buttons with holes, gradients, semi-transparency, even animations!

Windows XP通过UxTheme系统库中的Win32 API引入了正确的UI主题。2001年,我参加了微软在巴塞罗那举行的TechEd会议,以了解随着时间的推移,我们对该框架的期望。对于使用MFC或Win32 API开发自定义控件的观众来说,这种可能性似乎无穷无尽,而且令人恐惧。我记得谈论过圆形UI元素、带孔的按钮、渐变、半透明,甚至动画!

We had already been working on Qt's Windows XP style implementation based on the Windows XP preview builds, and used the new native APIs to draw the various elements of user interface controls. That work influenced a lot of the QStyle API design, just in time for the then-upcoming Qt 3 release. And the QStyle API is still largely the same in Qt 6's QtWidgets. The implementation of the Windows XP style later became the basis for the Windows Vista style, and for Qt 6, we use that implementation in the native Windows desktop style for Qt Quick Controls.

我们已经在研究Qt基于Windows XP预览版本的Windows XP风格的实现,并使用新的本地API绘制用户界面控件的各种元素。这项工作影响了QStyleAPI的许多设计,正好赶上即将发布的Qt3。Qt6的QtWidgets中的QStyleAPI基本上还是一样的。Windows XP风格的实现后来成为了Windows Vista风格的基础,对于Qt 6,我们在Qt Quick Controls中使用了原生Windows桌面风格的实现。

But fashion changes, and not all technologies evolve as originally intended. The expectation was perhaps that a community of creators would build lots of custom UI themes for the UxTheme library, similar to the many cursor and icon libraries. That did not really happen, and while buttons are nowadays just a flat frame with rounded corners, they - fortunately, I suppose - still have no holes.

但时代在改变,并不是所有的技术都按照最初的方向发展。人们的期望可能是,一个创作者社区将为UxTheme库构建许多自定义UI主题,类似于许多光标和图标库。这并没有真的发生,虽然按钮现在只是一个带圆角的平面框架,但幸运的是,我想它们仍然没有孔。

The UxTheme API is still present on Windows 11, and Qt still uses it to render the elements of user interface controls in the native Windows Vista style. However, the control assets we get are still based on the Aero design system of Windows Vista. And in that design system, there is no "dark mode", and there is no documented way to get the dark control assets through that API. So while Qt can read a dark palette from the system, we can't really use it when the UxTheme based Vista style is used - we'd get dark theme colors for some UI elements, but light UI control assets from the system, leaving the user with an unusable user interface.

UxTheme API仍然存在于Windows 11上,Qt仍然使用它以原生Windows Vista风格呈现用户界面控件的元素。然而,我们获得的控制资产仍然基于Windows Vista的Aero设计系统。在该设计系统中,没有“暗模式”,也没有通过该API获取暗控制资产的文档化方法。因此,虽然Qt可以从系统中读取深色调色板,但当使用基于UxTheme的Vista风格时,我们无法真正使用它-我们会为一些UI元素提供深色主题颜色,但从系统中获取浅色UI控件资产,从而给用户留下不可用的用户界面。

In recent years, Microsoft has moved towards the Fluent design system, which the Windows 11 system UI is based on. However, that system is not available through UxTheme, and so it is perhaps not a surprise that on a Windows 11 system, even the operating system UI comes in a mix of styles. Applications and system dialogs not written with the relatively new WinUI library don't look "fluent", often don't support the dark color scheme, and some control panels deeper down in the tree still look like they used to with Windows 2000.

近年来,微软已经转向了Fluent设计系统,Windows 11系统用户界面基于该系统。然而,该系统无法通过UxTheme获得,因此,在Windows 11系统上,即使操作系统用户界面也有多种风格,这或许并不令人惊讶。未使用相对较新的WinUI库编写的应用程序和系统对话框看起来不“流畅”,通常不支持深色方案,树中更深处的一些控制面板看起来仍然像Windows 2000。

Before Qt 6.5

Qt 6.5之前

Since version 5.15, Qt has provided an opt-in way to use the dark system palette, or to respect the dark system theme at least for the window decoration. That opt-in is a parameter to the QPA platform, and could be set through a command line option when starting the application:

从5.15版开始,Qt提供了一种选择使用暗系统调色板的方式,或者至少在窗户装饰上暗系统主题。opt-in是QPA平台的一个参数,可以在启动应用程序时通过命令行选项进行设置:

gallery.exe -platform windows:darkmode=1
gallery.exe -platform windows:darkmode=2

or through an environment variable (preferably set in the main function via qsetenv("QT_QPA_PLATFORM", "windows:darkmode=[1|2]")).

或通过环境变量(最好在主函数中通过qsetenv("QT_QPA_PLATFORM", "windows:darkmode=[1|2]")设置)。

The darkmode value of '1' enables window decoration theming, allowing applications that implement a custom palette and corresponding style to have a consistent window frame and title bar. The value '2' will in addition make Qt read and use the dark system palette. The default up to Qt 6.4 was to support neither.

深色模式值“1”启用窗口装饰主题,允许实现自定义调色板和相应样式的应用程序具有一致的窗口框架和标题栏。此外,值“2”将使Qt读取并使用暗系统调色板。Qt 6.4之前的默认值是两者都不支持。

In Qt 6.4 we changed the default behavior depending on the application default palette: if the application palette is dark, then windows automatically use the dark window decoration. To determine whether the palette is dark or light, we compare the window color with the text color:

在Qt 6.4中,我们根据应用程序默认调色板更改了默认行为:如果应用程序调色板为深色,则窗口自动使用深色窗口装饰。为了确定调色板是暗还是亮,我们将窗口颜色与文本颜色进行比较:

static bool shouldApplyDarkFrame()
{
    // ...
    const QPalette defaultPalette;
    return defaultPalette.color(QPalette::WindowText).lightness()
         > defaultPalette.color(QPalette::Window).lightness();
}

Applications can then use a style that looks good with a dark palette, set a dark palette, and automatically get a dark window title and frame.

然后,应用程序可以使用与深色调色板一起看起来很好的样式,设置深色调色板,并自动获得深色窗口标题和框架。

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    app.setStyle("fusion"); // looks good with dark color scheme
    app.setPalette(myDarkPalette());

    MainWindow mainWindow;
    mainWindow.show();
    return app.exec();
}

The problem is still that the dark palette is not read from the system and needs to be hand-crafted, unless darkmode=2 is specified. And if darkmode=2 is specified, then a dark palette is used even if the style cannot possible work with a dark color scheme. Also, there is no Qt API to find out whether the system is running with a dark or light color scheme.

问题仍然是,除非指定了darkmode=2,否则深色调色板无法从系统中读取,需要手工处理。如果指定了darkmode=2,则使用深色调色板,即使该样式无法使用深色方案。此外,没有QtAPI来确定系统是使用深色还是浅色方案运行。

The Qt 6.5 Way

Qt 6.5的方式

In Qt 6.5 we are taking the next step, while trying to keep things unchanged for existing applications.

在Qt 6.5中,我们正在采取下一步,同时努力保持现有应用程序的不变。

QStyleHints has a new property, colorScheme, that holds a Qt::ColorScheme enum value, either Qt::ColorScheme::Light or Qt::ColorScheme::Dark (or Qt::ColorScheme::Unknown on systems where there is no such system color scheme). This allows applications to determine whether a hand-crafted application palette should be dark or light, respecting the user's system preference. And like all good properties, it comes with a change notification signal QStyleHints::colorSchemeChanged that allows applications to respond to changes in the system color scheme.

QStyleHints有一个新属性colorScheme,该属性包含Qt::colorScheme枚举值,Qt::colorScheme::Light或Qt::colorScheme::Dark(在没有这样的系统颜色方案的系统上为Qt::colorScheme::Unknown)。这允许应用程序根据用户的系统偏好确定手工编写的应用程序调色板是暗还是亮。和所有好的属性一样,它附带了一个更改通知信号QStyleHints::colorSchemeChanged,允许应用程序响应系统颜色方案中的更改。

But ideally you don't have to hand-craft a palette anymore anyway - it's frankly a slippery slope to override user preferences, especially when considering users with a need for e.g. high-contrast user interfaces.

但理想情况下,你不必再手工编写调色板了——坦率地说,这是一个很难覆盖用户偏好的斜坡,尤其是在考虑需要高对比度用户界面的用户时。

Qt now always loads the system palette, which is based on the user's preference - in Qt 6.5 also on the Gnome desktop, by the way. However, as explained above, not all styles can look good with any palette, and the Windows Vista style definitely can't. So a style can decide to ignore that system palette, and overwrite it with a different palette, using existing polishing infrastructure in QStyle (and equivalent theme overrides in Qt Quick styles). The Windows Vista style will always replace the system palette with the light system palette. Styles that work well with any palette, such as the "Fusion" or classic Windows style, will leave the application palette unmodified.

Qt现在总是加载基于用户偏好的系统调色板,顺便说一句,Qt 6.5也在Gnome桌面上。然而,正如上面所解释的,并不是所有的样式都可以与任何调色板一起使用,而Windows Vista样式肯定不能。因此,样式可以决定忽略该系统调色板,并使用QStyle中的现有抛光基础设施(以及QtQuick样式中的等效主题覆盖)用不同的调色板覆盖它。Windows Vista样式将始终用灯光系统选项板替换系统选项板。与任何调色板配合良好的样式,如“Fusion”或经典的Windows样式,将使应用程序调色板保持不变。

This screenshot shows the widget "gallery" example (from my local dev branch, but you'll get the same results with the Qt 6.5 beta packages). On the left side it is running the default Windows style, and on the right side it was started with the -style fusion command line option. We are not changing the default style in Qt on Windows, so by default, your application will use the Windows Vista style, which will use the light system palette even on a Windows 11 system running with a dark theme. The window framing will be consistent with the application palette.

这张截图显示了widget“gallery”示例(来自我的本地开发分支,但Qt 6.5测试包也会得到同样的结果)。在左侧,它运行默认的Windows样式,在右侧,它使用-style fusion命令行选项启动。我们没有在Windows上更改Qt中的默认样式,因此默认情况下,您的应用程序将使用Windows Vista样式,即使在运行深色主题的Windows 11系统上,也将使用浅色系统调色板。窗口框架将与应用程序调色板一致。

But now applications can easily enable dark mode support, while respecting the user's preferences for their personal color scheme: you only have to set a style that works. In a Qt Quick application that would be:

但现在,应用程序可以轻松启用暗模式支持,同时尊重用户对其个人配色方案的偏好:您只需设置一种有效的样式即可。在Qt Quick应用程序中:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickStyle>

using namespace Qt::StringLiterals;

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

     QQuickStyle::setStyle("fusion");
     QQmlApplicationEngine engine;

     engine.load(QUrl(u"qrc:/main.qml"_s));

     return app.exec();
}

The Fusion style is our preferred style for Windows 11. It looks good with dark and light palette, and while it does not speak the Fluent design language, it blends rather well into the Windows 11 desktop.

Fusion样式是Windows 11的首选样式。它使用深色和浅色调色板看起来很不错,虽然它不会说流利的设计语言,但它很好地融入了Windows 11桌面。

What else to think about

还有什么值得考虑的

There are few things to check in your application before opting into the support of a dark color scheme.

在选择支持深色方案之前,您的应用程序中需要检查的内容很少。

If you have written your own style or use a style sheet, then you might perhaps hardcode certain colors. For instance, it's not unusual to make the text of a disabled button a bit lighter so that it looks "grayed out". However, if the color scheme is dark, then you will typically want to make the light text a bit darker instead.

如果您已经编写了自己的样式或使用了样式表,那么您可能会对某些颜色进行硬编码。例如,将禁用按钮的文本变浅一点以使其看起来“灰显”并不罕见。但是,如果配色方案是深色的,那么通常需要将浅色文本改为稍暗一些。

And if your application defines custom colors for certain visual elements, such as graphs, then you will also have to make sure that the colors you choose make sense when the background is dark and the foreground is light. You might even consider giving the user the option to flip between dark and light palettes for certain UI elements, e.g. when displaying rich text that might contain hard coded colors.

如果您的应用程序为某些视觉元素(如图形)定义了自定义颜色,那么您还必须确保所选的颜色在背景较暗而前景较亮时有意义。您甚至可以考虑为用户提供在某些UI元素的深色和浅色调色板之间切换的选项,例如,当显示可能包含硬编码颜色的富格文本时。

Beyond Qt 6.5

超越Qt 6.5

There are a few simple (but not necessarily easy) things we might want to add in future versions of Qt.

我们可能想在Qt的未来版本中添加一些简单(但不一定容易)的内容。

We might want to add a QPalette::colorScheme member that evaluates the palette's colors to determine whether the palette is dark or light. An application's choice of color for custom visual elements should be based on the actual palette used, rather than on the QStyleHints::colorScheme value. A member function like the simple shouldApplyDarkFrame() helper above would make that easy.

我们可能需要添加一个QPalette::colorScheme成员,它评估调色板的颜色,以确定调色板是暗还是亮。应用程序为自定义视觉元素选择的颜色应该基于实际使用的调色板,而不是基于QStyleHints::colorScheme值。像上面简单的shouldApplyDarkFrame()助手这样的成员函数会使这变得容易。

A common request is to make the QStyleHints::colorScheme a writable property, so that applications can force a certain color scheme, no matter the system setting, and including the window frame. This will have limitations on some platforms - on Windows, we don't think it's possible to force a dark window decoration on an otherwise light system, while macOS allows us to control the appearance separately for each window.

一个常见的请求是将QStyleHints::colorScheme设置为可写属性,这样无论系统设置如何,应用程序都可以强制使用特定的颜色方案,包括窗框。这在某些平台上会有限制——在Windows上,我们认为不可能在其他亮系统上强制使用深色窗口装饰,而macOS允许我们单独控制每个窗口的外观。

When we read the dark system palette on Windows, then we use the theme's accent color for the QPalette::Highlight color role. This is however not quite correct, as the Accent is used in other places as well, and some controls use different colors (i.e. on Windows 11's "red" dark theme, the highlight is bright red, while the focus frames are in a paler orange). QPalette doesn't have an Accent color role right now, and adding that is a bit complex as the internal QPalette data structures need to change quite a bit once we go above 21 color roles - and we are at 21 already.

当我们在Windows上阅读深色系统调色板时,我们将主题的accent色用于QPalette::Highlight颜色角色。然而,这并不完全正确,因为Accent也在其他地方使用,并且一些控件使用不同的颜色(即,在Windows 11的“红色”暗主题上,高亮显示为亮红色,而焦点框为浅橙色)。QPalette目前没有Accent颜色角色,而且补充说,这有点复杂,因为一旦我们超过21个颜色角色,QPalette内部数据结构需要进行相当大的更改,而我们已经达到了21个。

Fluent Design with Figma

使用Figma进行流畅设计

And we do want to bring a style that implements the Fluent design system to Qt as well. The Fluent design system is available as an open source Figma package, and Brook has recently blogged about using Figma designs with Qt Quick Controls. That is a path we are following further right now: we would like to make the visual assets in a Figma design available to Qt Quick user interfaces, and maybe even to QtWidgets UIs. This can probably be achieved with a mix of import/export bridges, Qt Design Studio integration, and build system tools. A convincing native look of Qt applications on Windows based on the Fluent design provided by Microsoft will be a good benchmark for this work.

我们也希望为Qt带来一种实现Fluent设计系统的风格。Fluent设计系统是一个开源的Figma包,Brook最近在博客中介绍了将Figma设计与Qt Quick Controls结合使用。这是我们现在正在进一步遵循的一条路径:我们希望将Figma设计中的视觉资产用于QtQuick用户界面,甚至可能用于QtWidgets UI。这可能可以通过混合导入/导出桥、QtDesignStudio集成和构建系统工具来实现。基于微软提供的Fluent设计的Windows上的Qt应用程序的令人信服的原生外观将是这项工作的良好基准。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值