Qt 中实现系统主题感知

【写在前面】

在现代桌面应用程序开发中,系统主题感知是一项重要的功能,它使得应用程序能够根据用户的系统主题设置(如深色模式或浅色模式)自动调整其外观。

Qt 作为一个跨平台的C++图形用户界面应用程序开发框架,提供了丰富的工具和类来实现这一功能。


【正文开始】

一、使用效果

Qt 中实现系统主题感知

二、系统主题感知助手类(SystemThemeHelper)

SystemThemeHelper类是一个封装了系统主题感知功能的Qt对象。它主要通过读取系统设置和监听系统主题变化来更新应用程序的主题颜色和颜色方案。

  1. 类定义与属性

    systemthemehelper.h中,SystemThemeHelper类继承自QObject,并定义了两个属性:themeColorcolorScheme。这两个属性分别表示当前的主题颜色和颜色方案(深色、浅色或无)。

    class SystemThemeHelper : public QObject {     Q_OBJECT     Q_PROPERTY(QColor themeColor READ themeColor NOTIFY themeColorChanged)     Q_PROPERTY(SystemThemeHelper::ColorScheme colorScheme READ colorScheme NOTIFY colorSchemeChanged)     // ... }; 

    ColorScheme是一个枚举类,定义了三种颜色方案:NoneDarkLight

  2. 构造函数与析构函数

    SystemThemeHelper的构造函数初始化了一些私有成员变量,并启动了一个定时器,用于定期更新主题颜色和颜色方案。析构函数则负责清理资源。

    SystemThemeHelper::SystemThemeHelper(QObject *parent)     : QObject{parent}, d_ptr(new SystemThemeHelperPrivate(this)) {     Q_D(SystemThemeHelper);     d->m_themeColor = getThemeColor();     d->m_colorScheme = getColorScheme();     d->m_timer.start(200, this);     #ifdef Q_OS_WIN     initializeFunctionPointers();     #endif }  SystemThemeHelper::~SystemThemeHelper() {     // 清理资源 } 
  3. 获取主题颜色和颜色方案

    getThemeColorgetColorScheme是两个不可用于绑定的方法,它们立即返回当前的主题颜色和颜色方案,但不会触发任何更新通知。这两个方法主要用于快速获取当前设置,而不关心后续的变化。

    QColor SystemThemeHelper::getThemeColor() const {     Q_D(const SystemThemeHelper);     #ifdef Q_OS_WIN     return QColor::fromRgb(d->m_themeColorSettings.value("ColorizationColor").toUInt());     #endif }  SystemThemeHelper::ColorScheme SystemThemeHelper::getColorScheme() const {     Q_D(const SystemThemeHelper);     #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)     const auto scheme = QGuiApplication::styleHints()->colorScheme();     return scheme == Qt::ColorScheme::Dark ? ColorScheme::Dark : ColorScheme::Light;     #else     #ifdef Q_OS_WIN     return !d->m_colorSchemeSettings.value("AppsUseLightTheme").toBool() ? ColorScheme::Dark : ColorScheme::Light;     #else //linux     const QPalette defaultPalette;     const auto text = defaultPalette.color(QPalette::WindowText);     const auto window = defaultPalette.color(QPalette::Window);     return text.lightness() > window.lightness() ? ColorScheme::Dark : ColorScheme::Light;     #endif // Q_OS_WIN     #endif // QT_VERSION } 
  4. 更新主题颜色和颜色方案

    themeColorcolorScheme是两个可用于绑定的方法,它们返回当前的主题颜色和颜色方案,并在值发生变化时发出通知。这两个方法内部调用了私有成员函数的更新逻辑。

    QColor SystemThemeHelper::themeColor() {     Q_D(SystemThemeHelper);     d->_updateThemeColor();     return d->m_themeColor; }  SystemThemeHelper::ColorScheme SystemThemeHelper::colorScheme() {     Q_D(SystemThemeHelper);     d->_updateColorScheme();     return d->m_colorScheme; } 
  5. 设置窗口标题栏模式

    setWindowTitleBarMode方法允许设置窗口标题栏的模式(深色或浅色)。这个方法在Windows平台上通过调用 DWM API 实现,而在其他平台上则不支持。

    bool SystemThemeHelper::setWindowTitleBarMode(QWindow *window, bool isDark) {     #ifdef Q_OS_WIN     return bool(pDwmSetWindowAttribute ? !pDwmSetWindowAttribute(HWND(window->winId()), 20, &isDark, sizeof(BOOL)) : false);     #else     return false;     #endif //Q_OS_WIN } 
  6. 定时器事件处理

    timerEvent方法是一个虚函数,用于处理定时器事件。它定期调用更新函数来检查主题颜色和颜色方案是否发生变化,并在变化时发出通知。

    void SystemThemeHelper::timerEvent(QTimerEvent *) {     Q_D(SystemThemeHelper);     d->_updateThemeColor();     d->_updateColorScheme(); } 

三、实现细节

SystemThemeHelperPrivateSystemThemeHelper的私有实现类,它封装了所有的实现细节和状态变量。这个类主要负责读取系统设置、更新主题颜色和颜色方案,并发出通知。

  1. 构造函数与成员变量

    SystemThemeHelperPrivate的构造函数接收一个指向SystemThemeHelper的指针,并初始化成员变量。成员变量包括主题颜色、颜色方案、定时器和一些平台特定的设置对象。

    SystemThemeHelperPrivate::SystemThemeHelperPrivate(SystemThemeHelper *q)     : q_ptr(q) {     // 初始化成员变量 } 
  2. 更新函数

    _updateThemeColor_updateColorScheme是两个更新函数,它们检查当前的主题颜色和颜色方案是否发生变化,并在变化时更新成员变量并发出通知。

    void SystemThemeHelperPrivate::_updateThemeColor() {     Q_Q(SystemThemeHelper);     auto nowThemeColor = q->getThemeColor();     if (nowThemeColor != m_themeColor) {         m_themeColor = nowThemeColor;         emit q->themeColorChanged();     } }  void SystemThemeHelperPrivate::_updateColorScheme() {     Q_Q(SystemThemeHelper);     auto nowColorScheme = q->getColorScheme();     if (nowColorScheme != m_colorScheme) {         m_colorScheme = nowColorScheme;         emit q->colorSchemeChanged();     } } 
  3. 平台特定的实现

    在Windows平台上,SystemThemeHelperPrivate使用QSettings来读取系统主题设置,并使用DWM API来设置窗口标题栏的模式。这些实现细节被封装在条件编译块中,以确保跨平台的兼容性。

    #ifdef Q_OS_WIN QSettings m_themeColorSettings{QSettings::UserScope, "Microsoft", "Windows\DWM"}; QSettings m_colorSchemeSettings{QSettings::UserScope, "Microsoft", "Windows\CurrentVersion\Themes\Personalize"}; static DwmSetWindowAttributeFunc pDwmSetWindowAttribute = nullptr; // ... static inline bool initializeFunctionPointers() {     // 初始化DWM API函数指针 } #endif //Q_OS_WIN 

四、如何使用

C++:

	SystemThemeHelper *helper = new SystemThemeHelper;     QObject::connect(helper, &SystemThemeHelper::themeColorChanged, [helper]{         qDebug() << helper->getThemeColor();     });     QObject::connect(helper, &SystemThemeHelper::colorSchemeChanged, [helper]{         qDebug() << helper->getColorScheme();     }); 

Qml:

import QtQuick 2.15 import QtQuick.Window 2.15  import DelegateUI.Utils 1.0  Window {     id: window     width: 640     height: 480     visible: true     title: qsTr("SystemThemeHelper Test - ") + (themeHelper.colorScheme == SystemThemeHelper.Dark ? "Dark" : "Light")     color: themeHelper.colorScheme == SystemThemeHelper.Dark ? "black" : "white"      Behavior on color { ColorAnimation { } }      SystemThemeHelper {         id: themeHelper         onThemeColorChanged: {             console.log("onThemeColorChanged:", themeColor);         }         onColorSchemeChanged: {             setWindowTitleBarMode(window, themeHelper.colorScheme == SystemThemeHelper.Dark)             console.log("onColorSchemeChanged:", colorScheme);         }         Component.onCompleted: {             console.log("onColorSchemeChanged:", colorScheme);             setWindowTitleBarMode(window, themeHelper.colorScheme == SystemThemeHelper.Dark)         }     }      Text {         anchors.centerIn: parent         text: qsTr("主题颜色")         font.family: "微软雅黑"         font.pointSize: 32         color: themeHelper.themeColor     } }  

【结语】

通过SystemThemeHelper类,我们可以在 Qt 应用程序中实现系统主题感知功能。

这个类封装了读取系统设置、更新主题颜色和颜色方案以及发出通知的逻辑,使得我们可以轻松地根据系统主题变化来调整应用程序的外观。

此外,通过条件编译和平台特定的实现,还确保了跨平台的兼容性。

最后:项目链接(多多star呀..⭐_⭐):

Github: https://github.com/mengps/QmlControls

Gitee: https://gitee.com/MenPenS/QmlControls

发表评论

相关文章