以下是针对 Qt 5.12.9 的完整适配方案,包含必要的代码修正和兼容性调整:
// thememanager.h
#ifndef THEMEMANAGER_H
#define THEMEMANAGER_H
#include
#include
#include
#include
class ThemeManager : public QObject
{
Q_OBJECT
public:
struct ShadowConfig {
QColor color;
qreal radius;
QPoint offset;
ShadowConfig(QColor c = Qt::black, qreal r = 0, QPoint o = QPoint())
: color(c), radius(r), offset(o) {}
};
static ThemeManager& instance();
// 注册控件并应用阴影
void registerWidget(QWidget* widget, const QString& configName = "default");
void applyTheme(const QString& themeName);
// QML可访问接口
Q_INVOKABLE QColor getShadowColor(const QString& configName = "default") const;
Q_INVOKABLE qreal getShadowRadius(const QString& configName = "default") const;
Q_INVOKABLE QPoint getShadowOffset(const QString& configName = "default") const;
signals:
void themeChanged();
private:
explicit ThemeManager(QObject* parent = nullptr);
void loadThemeConfig(const QString& themePath);
void applyShadowEffect(QWidget* widget, const QString& configName); // 私有方法声明
QHash<QString, ShadowConfig> m_shadowConfigs;
QHash<QWidget*, QString> m_registeredWidgets;
};
#endif // THEMEMANAGER_H
// thememanager.cpp
#include "thememanager.h"
#include
#include
#include
#include
#include
ThemeManager& ThemeManager::instance()
{
static ThemeManager instance;
return instance;
}
ThemeManager::ThemeManager(QObject* parent) : QObject(parent)
{
// 初始化默认配置
m_shadowConfigs["default"] = ShadowConfig(QColor(43,43,43), 30, QPoint(0,5));
m_shadowConfigs["navigation"] = ShadowConfig(QColor(43,43,43), 30, QPoint(0,5));
m_shadowConfigs["workarea"] = ShadowConfig(QColor(43,43,43), 10, QPoint(5,5));
}
void ThemeManager::registerWidget(QWidget* widget, const QString& configName)
{
if(widget && m_shadowConfigs.contains(configName)){
m_registeredWidgets.insert(widget, configName);
applyShadowEffect(widget, configName);
}
}
void ThemeManager::applyTheme(const QString& themeName)
{
loadThemeConfig(themeName);
// 更新所有已注册控件
QHashIterator<QWidget*, QString> it(m_registeredWidgets);
while (it.hasNext()) {
it.next();
applyShadowEffect(it.key(), it.value());
}
emit themeChanged();
}
void ThemeManager::loadThemeConfig(const QString& themePath)
{
QFile file(themePath);
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "Theme file not found:" << themePath;
return;
}
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
if (error.error != QJsonParseError::NoError) {
qWarning() << "JSON parse error:" << error.errorString();
return;
}
QJsonObject root = doc.object();
QJsonObject shadows = root["shadows"].toObject();
foreach(const QString& key, shadows.keys()) {
QJsonObject config = shadows[key].toObject();
ShadowConfig sc;
sc.color = QColor(config["color"].toString());
sc.radius = config["radius"].toDouble();
QJsonArray offset = config["offset"].toArray();
if (offset.size() >= 2) {
sc.offset = QPoint(offset[0].toInt(), offset[1].toInt());
}
m_shadowConfigs[key] = sc;
}
}
void ThemeManager::applyShadowEffect(QWidget* widget, const QString& configName)
{
if (!m_shadowConfigs.contains(configName)) return;
const ShadowConfig& config = m_shadowConfigs[configName];
QGraphicsDropShadowEffect* effect = nullptr;
if (widget->graphicsEffect()) {
effect = qobject_cast<QGraphicsDropShadowEffect*>(widget->graphicsEffect());
} else {
effect = new QGraphicsDropShadowEffect(widget);
widget->setGraphicsEffect(effect);
}
if (effect) {
effect->setColor(config.color);
effect->setBlurRadius(config.radius);
effect->setOffset(config.offset);
}
}
// QML属性访问
QColor ThemeManager::getShadowColor(const QString& configName) const
{
return m_shadowConfigs.value(configName).color;
}
qreal ThemeManager::getShadowRadius(const QString& configName) const
{
return m_shadowConfigs.value(configName).radius;
}
QPoint ThemeManager::getShadowOffset(const QString& configName) const
{
return m_shadowConfigs.value(configName).offset;
}
// resultgraph.cpp(修改后)
#include "thememanager.h"
ResultGraph::ResultGraph(QWidget *parent) :
QWidget(parent),
ui(new Ui::ResultGraphScreen)
{
ui->setupUi(this);
// 自动注册控件(无需提升)
auto registerWidgets = {
ui->base_navigationbar,
ui->styleBar,
ui->graphWorkplace
};
foreach(auto widget, registerWidgets) {
ThemeManager::instance().registerWidget(widget);
}
// 应用初始主题
ThemeManager::instance().applyTheme(":/themes/dark.json");
// ...保持其他初始化代码...
}
// ThemeWrapper.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
Item {
property alias sourceComponent: loader.sourceComponent
property string configName: "default"
Loader {
id: loader
onLoaded: {
ThemeManager.registerWidget(item, configName)
}
}
Connections {
target: ThemeManager
onThemeChanged: {
if (loader.item) {
ThemeManager.registerWidget(loader.item, configName)
}
}
}
}
// 使用示例
import QtQuick 2.12
import QtQuick.Controls 2.12
ThemeWrapper {
configName: "workarea"
sourceComponent: Rectangle {
width: 200
height: 100
color: "white"
radius: 4
}
}
// themes/dark.json
{
"shadows": {
"default": {
"color": "#2B2B2B",
"radius": 30,
"offset": [0, 5]
},
"navigation": {
"color": "#2B2B2B",
"radius": 30,
"offset": [0, 5]
},
"workarea": {
"color": "#404040",
"radius": 15,
"offset": [3, 3]
}
}
}
// main.cpp
#include
#include
#include "thememanager.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// 注册QML类型(Qt5.12方式)
qmlRegisterSingletonType<ThemeManager>("App.Theme", 1, 0, "ThemeManager",
[](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject* {
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
return &ThemeManager::instance();
});
// 加载QML
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
// 显示Widgets窗口
MainWindow w;
w.show();
return app.exec();
}
头文件完整性:
applyShadowEffect
私有方法QML_ELEMENT
宏Qt5.12 兼容性:
QHashIterator
替代 C++11 范围 forQ_INVOKABLE
替代属性绑定自动注册机制:
// 自动发现控件示例
void findAndRegister(QWidget* parent) {
foreach(QObject* obj, parent->children()) {
if(auto widget = qobject_cast<QWidget*>(obj)) {
if(widget->objectName().startsWith("shadow_")) {
ThemeManager::instance().registerWidget(widget);
}
findAndRegister(widget); // 递归查找
}
}
}
性能优化:
// 效果对象池(头文件中添加)
class ShadowPool {
public:
static QGraphicsDropShadowEffect* getEffect(const ThemeManager::ShadowConfig& config) {
static QVector<QSharedPointer<QGraphicsDropShadowEffect>> pool;
// 查找匹配配置
auto it = std::find_if(pool.begin(), pool.end(), [&](const auto& ptr){
return ptr->color() == config.color &&
qFuzzyCompare(ptr->blurRadius(), config.radius) &&
ptr->offset() == config.offset;
});
if(it != pool.end()) return it->data();
// 创建新效果
auto effect = QSharedPointer<QGraphicsDropShadowEffect>::create();
effect->setColor(config.color);
effect->setBlurRadius(config.radius);
effect->setOffset(config.offset);
pool.append(effect);
return effect.data();
}
};
// 修改applyShadowEffect
void ThemeManager::applyShadowEffect(...) {
// ...
effect = ShadowPool::getEffect(config);
widget->setGraphicsEffect(effect);
// ...
}
文件结构:
project/
├── core/
│ ├── thememanager.h
│ └── thememanager.cpp
├── resources/
│ └── themes/
│ ├── dark.json
│ └── light.json
└── qml/
└── components/
└── ThemeWrapper.qml
资源文件配置:
themes/dark.json
themes/light.json
qml/components/ThemeWrapper.qml
编译要求:
# Qt5.12项目配置
QT += core gui qml quick widgets
CONFIG += c++11
RESOURCES += resources.qrc
该方案完整适配 Qt5.12.9,具有以下优势:
4. 无需设计时修改:通过代码自动注册控件
5. 完整类型安全:使用 qobject_cast 进行类型验证
6. 内存高效:采用对象池管理阴影效果
7. 多主题支持:通过 JSON 动态加载配置
8. 混合开发友好:统一管理 QML 和 Widgets 的主题
验证方法:
9. 切换主题时观察控件阴影参数变化
10. 在低端设备上测试内存占用(应 < 80MB)
11. 验证 JSON 配置错误时的默认值恢复机制
12. 测试同时存在 100+ 控件时的切换性能
13.
以下是针对您提供的 ResultGraph
类的完整修改方案,实现主题化阴影效果管理:
#include "thememanager.h" // 添加头文件包含
ResultGraph::ResultGraph(QWidget *parent) : QWidget(parent), ui(new Ui::ResultGraphScreen)
{
ui->setupUi(this);
// ================ 主题化阴影设置 ================
auto& themeMgr = ThemeManager::instance();
// 注册需要阴影效果的控件
themeMgr.registerWidget(ui->base_navigationbar, "navigation");
themeMgr.registerWidget(ui->graphWorkplace, "workarea");
themeMgr.registerWidget(ui->styleBar, "style");
// 应用初始主题(在main.cpp中全局应用更合适)
themeMgr.applyTheme(":/themes/dark.json");
// ================ 移除原有阴影设置代码 ================
// 删除以下代码:
// QGraphicsDropShadowEffect *base_navigationbarshadow = new ...
// QGraphicsDropShadowEffect *graphWorkAreaShadow = new ...
// QGraphicsDropShadowEffect *styleBarShadow = new ...
// ================ 保持原有其他初始化代码 ================
// 整体值
prograssBar_V_OP = new overallValuesPrograssBar(this);
prograssBar_V_RMS = new overallValuesPrograssBar(this);
prograssBar_A_OP = new overallValuesPrograssBar(this);
prograssBar_A_RMS = new overallValuesPrograssBar(this);
addOverallValue(prograssBar_V_OP, 15, ui->gridLayout);
addOverallValue(prograssBar_V_RMS, 60, ui->gridLayout_4);
addOverallValue(prograssBar_A_OP, 20, ui->gridLayout_5);
addOverallValue(prograssBar_A_RMS, 30, ui->gridLayout_6);
// 上图表
resultBigraph = new Bigraph(ui->upGraph);
sineGenerator = new SineGenerator(this);
sineGenerator->configure(1000, 1, 44100);
QVector<qreal> waveform = sineGenerator->generate(1000);
resultBigraph->addFrontSeriesPoint(0, 0);
resultBigraph->addBackSeriesPoint(0, 0);
for(int i = 0; i < waveform.size(); i++)
{
resultBigraph->addFrontSeriesPoint(i, waveform[i]);
resultBigraph->addBackSeriesPoint(i, waveform[i]);
}
resultBigraph->addFrontSeriesPoint(1000, 0);
resultBigraph->addBackSeriesPoint(1000, 0);
resultBigraph->adjustAxisRanges();
resultBigraph->frontAxisX->setTitleText("f[Hz]");
resultBigraph->frontAxisY->setTitleText("v[mm/s]");
resultBigraph->backChart->setTitle("PlaneA Speed");
QVBoxLayout *upGraphLayout = new QVBoxLayout(ui->upGraph);
upGraphLayout->addWidget(resultBigraph);
// 下图表
resultDownBigraph = new Bigraph(ui->upGraph);
resultDownBigraph->addFrontSeriesPoint(0, 0);
resultDownBigraph->addBackSeriesPoint(0, 0);
resultDownBigraph->addFrontSeriesPoint(1000, 0);
resultDownBigraph->addBackSeriesPoint(1000, 0);
resultDownBigraph->adjustAxisRanges();
resultDownBigraph->frontAxisX->setTitleText("t[s]");
resultDownBigraph->frontAxisY->setTitleText("v[mm/s]");
resultDownBigraph->backChart->setTitle("PlaneA Speed");
QVBoxLayout *downGraphLayout = new QVBoxLayout(ui->downGraph);
downGraphLayout->addWidget(resultDownBigraph);
}
{
"shadows": {
"navigation": {
"color": "#2B2B2B",
"radius": 30,
"offset": [0, 5]
},
"workarea": {
"color": "#404040",
"radius": 10,
"offset": [5, 5]
},
"style": {
"color": "#2B2B2B",
"radius": 10,
"offset": [5, 5]
}
}
}
#include "thememanager.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 初始化主题(全局应用)
ThemeManager::instance().applyTheme(":/themes/dark.json");
// 注册QML类型(如果用到QML)
qmlRegisterSingletonType<ThemeManager>("App.Theme", 1, 0, "ThemeManager",
[](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject* {
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
return &ThemeManager::instance();
});
ResultGraph w;
w.show();
return a.exec();
}
// 在任意菜单或按钮点击事件中切换主题
void MainWindow::on_actionDark_triggered()
{
ThemeManager::instance().applyTheme(":/themes/dark.json");
}
void MainWindow::on_actionLight_triggered()
{
ThemeManager::instance().applyTheme(":/themes/light.json");
}
// 在ThemeManager中添加
void ThemeManager::applyThemeWithAnimation(const QString& themeName)
{
QPropertyAnimation* fadeOut = new QPropertyAnimation(this, "shadowOpacity");
fadeOut->setDuration(300);
fadeOut->setStartValue(1.0);
fadeOut->setEndValue(0.0);
QPropertyAnimation* fadeIn = new QPropertyAnimation(this, "shadowOpacity");
fadeIn->setDuration(300);
fadeIn->setStartValue(0.0);
fadeIn->setEndValue(1.0);
QSequentialAnimationGroup* group = new QSequentialAnimationGroup(this);
group->addAnimation(fadeOut);
group->addAnimation(fadeIn);
connect(group, &QAnimationGroup::finished, [=](){
loadThemeConfig(themeName);
updateAllEffects();
});
group->start();
}
void ThemeManager::applyShadowEffect(QWidget* widget, const QString& configName)
{
qDebug() << "Applying shadow to:" << widget->objectName()
<< "| Config:" << configName
<< "| Color:" << m_shadowConfigs[configName].color.name()
<< "| Radius:" << m_shadowConfigs[configName].radius
<< "| Offset:" << m_shadowConfigs[configName].offset;
// 原有实现...
}
// 在MainWindow构造函数中添加
void MainWindow::autoRegisterShadowWidgets()
{
const QStringList shadowWidgetNames = {
"base_navigationbar",
"graphWorkplace",
"styleBar"
};
auto registerChildren = [&](QWidget* parent){
foreach(QObject* obj, parent->children()){
if(auto widget = qobject_cast<QWidget*>(obj)){
if(shadowWidgetNames.contains(widget->objectName())){
ThemeManager::instance().registerWidget(widget);
}
registerChildren(widget); // 递归注册子控件
}
}
};
registerChildren(this);
}
该方案完整实现了以下功能: