CMake实战篇1-主题管理库
CMake实战篇1-主题管理库
《宿建德江》· 孟浩然
移舟泊烟渚,日暮客愁新。
野旷天低树,江清月近人。

在多 Qt 项目开发场景中,重复开发主题切换功能不仅耗时,还易导致代码不一致。为此,我们基于 CMake 构建了一款可直接复用的 Qt 主题管理器动态库,无需重复造轮子,让多个项目快速具备动态主题切换能力。
本文由 豆包AI 协助完成
一、核心用法:开箱即用的主题管理
这款动态库的设计核心是 “极简接入、灵活使用”,无需深入理解底层实现,仅需两步即可集成到任意 Qt 项目中。
1.1 快速集成
将编译好的动态库文件(Windows 下为.dll/.lib,Linux 下为.so,macOS 下为.dylib)和头文件拷贝到项目指定目录,在项目的 CMakeLists.txt 中仅需几行配置即可完成依赖引入:
find_package(UThemeManager REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE Hakuon::UThemeManager)
1.2 简单调用
在项目代码中,通过全局单例即可实现主题切换,无需额外初始化,核心调用仅需一行代码:
void UThemeManager::applyTheme(UThemeManager::ETheme theme)
{
QString typeName;
switch (theme)
{
case ET_DarkBlue:
typeName = "darkblue";
break;
case ET_Light:
typeName = "lightblue";
break;
default:
break;
}
applyTheme(QString(":/res/%1.qss").arg(typeName));
}
1.3 效果预览

二、核心优势:适配多场景的复用价值
2.1 跨项目复用,提效降本
将主题管理逻辑抽离为独立动态库,所有 Qt 项目无需重复编写样式表加载、主题切换代码,接入成本仅需几分钟,大幅减少重复开发工作量,且能保证所有项目的主题切换逻辑一致。
2.2 跨平台兼容,适配性强
基于 CMake 构建,天然支持 Windows、Linux、macOS 三大平台编译,编译产物可直接在对应平台使用,无需针对不同系统做额外适配,降低跨平台开发复杂度。
2.3 接口简洁,低学习成本
仅暴露核心的主题切换、自定义样式加载接口,无需掌握复杂的配置规则,即使是新手也能快速上手,且单例模式设计符合 Qt 项目的全局使用习惯。
2.4 灵活扩展,适配个性化需求
支持加载自定义 QSS 文件,不仅局限于内置的亮色 / 暗色主题,可根据不同项目的视觉风格,灵活接入专属主题样式,满足个性化需求。
三、使用注意事项与不足
3.1 运行时依赖
动态库需与项目运行环境匹配(如 Qt 版本、编译器、系统架构),若项目更换 Qt 版本或编译环境,需重新编译动态库,否则可能出现兼容性问题。
3.2 样式表冲突风险
若项目自身已设置局部样式表,可能与主题管理器的全局样式表产生冲突,需在使用时做好样式表的层级规划,避免样式覆盖异常。
3.3 调试难度略增
相较于项目内的本地代码,动态库的调试需要依赖调试符号文件(如 Windows 下的 PDB 文件),若缺失则难以定位库内的问题,增加调试成本。
3.4 功能轻量化,适配场景有限
当前版本仅聚焦核心的主题切换能力,未支持主题变量、多主题预览、样式缓存等进阶功能,若项目有复杂的主题管理需求,需在此基础上扩展。
四、总结
这款基于 CMake 的 Qt 主题管理器动态库,以 “复用” 为核心,解决了多 Qt 项目主题切换逻辑冗余的问题,凭借简洁的接入方式和跨平台特性,能快速落地到各类 Qt 项目中。虽然存在少量使用限制,但通过规范使用流程(如统一 Qt 编译环境、规划样式表层级)可有效规避,是提升多 Qt 项目开发效率的实用工具。
五.源码实现
#ifndef UTHEMEMANAGER_H
#define UTHEMEMANAGER_H
/*! ===================================================================
@class UThemeManager;
@brief 用于主题管理, 支持不同的主题皮肤;
@note note;
@author Hakuon
@date 2025-11-20
======================================================================*/
#include <QObject>
#include <QtCore/qglobal.h>
#ifndef BUILD_STATIC
# if defined(UTHEMEMANAGER_LIBRARY)
# define UTHEMEMANAGER_EXPORT Q_DECL_EXPORT
# else
# define UTHEMEMANAGER_EXPORT Q_DECL_IMPORT
# endif
#else
# define HAKUWIDGETS_EXPORT
#endif
class UTHEMEMANAGER_EXPORT UThemeManager
{
public:
enum ETheme {
ET_DarkBlue = 0,
ET_Light,
ET_None = 100,
};
~UThemeManager();
static UThemeManager* instance();
void applyTheme(ETheme theme = ET_DarkBlue);
void applyTheme(const QString& path);
public:
explicit UThemeManager();
};
#endif // UTHEMEMANAGER_H
#include "UThemeManager.h"
#include <QApplication>
#include <QDebug>
#include <QFile>
UThemeManager::UThemeManager()
{
}
UThemeManager::~UThemeManager()
{
}
UThemeManager *UThemeManager::instance()
{
static UThemeManager s_utm_inst;
return &s_utm_inst;
}
void UThemeManager::applyTheme(UThemeManager::ETheme theme)
{
QString typeName;
switch (theme)
{
case ET_DarkBlue:
typeName = "darkblue";
break;
case ET_Light:
typeName = "lightblue";
break;
default:
break;
}
applyTheme(QString(":/res/%1.qss").arg(typeName));
}
void UThemeManager::applyTheme(const QString &path)
{
QFile file(path);
if (file.open(QIODevice::Text | QIODevice::ReadOnly))
{
qApp->setStyleSheet(file.readAll());
}
file.close();
qDebug() << ((file.exists()) ? u8"加载主题管理器成功. ^_^" : u8"主题文件未找到. 加载失败 >_<");
}
CMakeLists.txt文件编写
cmake_minimum_required(VERSION 3.15)
# ------------------------------------
# 设置项目的基本信息
# ------------------------------------
project(UThemeManager
VERSION 1.0.0
LANGUAGES CXX
DESCRIPTION "A Custom Theme Manager"
)
# -------------------------------------------------
function(group_files_by_folder out_var folder_path file_glob_pattern group_name)
file(GLOB FILE_LIST "${folder_path}/${file_glob_pattern}")
if(FILE_LIST)
source_group("${group_name}" FILES ${FILE_LIST})
set(${out_var} ${FILE_LIST} PARENT_SCOPE)
endif()
endfunction()
# -------------------------------------------------
# ------------------------------------
# 文件分组
# ------------------------------------
group_files_by_folder(HEADERS ${CMAKE_CURRENT_SOURCE_DIR} "*.h" "Include")
group_files_by_folder(SOURCES ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp" "Src")
group_files_by_folder(RES ${CMAKE_CURRENT_SOURCE_DIR} "*.qrc" "res")
set(EXPORT_HEADERS
UThemeManager.h
)
# ------------------------------------
# 生成库
# ------------------------------------
add_library(${PROJECT_NAME} SHARED ${HEADERS} ${SOURCES} ${RES})
# ------------------------------------
# 区分构建和install后的头文件引用
# ------------------------------------
target_include_directories(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include/${PROJECT_NAME}>
)
set_target_properties(${PROJECT_NAME} PROPERTIES
DEBUG_POSTFIX "d"
PUBLIC_HEADER "${EXPORT_HEADERS}"
AUTORCC ON
AUTOUIC ON
AUTOMOC ON
)
target_compile_definitions(${PROJECT_NAME} PRIVATE UTHEMEMANAGER_LIBRARY)
find_package(Qt5 COMPONENTS Core Widgets REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Core Qt5::Widgets)
# ------------------------------------
# 安装属性
# ------------------------------------
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
# 安装目标文件
install(TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}Targets
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
# 导出目标信息
install(EXPORT ${PROJECT_NAME}Targets
FILE ${PROJECT_NAME}Targets.cmake
NAMESPACE Hakuon::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
# 生成配置文件
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
)
# 安装 config 文件
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
UThemeManagerConfig.cmake.in编写
# @PACKAGE_INIT@ 必须放在开头
@PACKAGE_INIT@
# 设置版本变量(可选但推荐), set(MyMath_VERSION 2.3.1)
set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@)
# 包含目标文件(核心), 一般值得是 lib\cmake\MyMath
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
# 提供传统变量(向后兼容),set(MyMath_LIBRARIES MyMath::MyMath)
set(@PROJECT_NAME@_LIBRARIES @PROJECT_NAME@::@PROJECT_NAME@)
# 检查必需组件(如果有)
check_required_components(@PROJECT_NAME@)
本文来自博客园,作者:Hakuon,转载请注明原文链接:https://www.cnblogs.com/Hakuon/p/19350148
浙公网安备 33010602011771号