From 68d832c57b4af73ef36d09a183b14bfb9141de75 Mon Sep 17 00:00:00 2001 From: gaozheng Date: Wed, 10 Jun 2026 09:32:22 +0800 Subject: [PATCH] =?UTF-8?q?fix(ela):=20=E7=99=BB=E5=BD=95=E7=AA=97?= =?UTF-8?q?=E4=B8=BB=E9=A2=98=E5=8C=96=20+=20VTK=20=E8=83=8C=E6=99=AF?= =?UTF-8?q?=E7=A8=B3=E5=81=A5=E9=9A=8F=E4=B8=BB=E9=A2=98=20+=20=E6=89=AB?= =?UTF-8?q?=E6=B8=85=E6=89=80=E6=9C=89=E7=A1=AC=E7=BC=96=E7=A0=81=E6=B5=85?= =?UTF-8?q?=E8=89=B2=20QSS=20=E9=81=97=E6=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 登录窗: setStyleSheet → applyThemedStyleSheet(整窗随主题, 品牌带文字用 white 关键字恒白); refreshBtn/errorLabel 也随主题。修暗系统下浅窗+暗 Ela 控件割裂、占位文字看不清 - VTK: 改为主题切换时重跑 rebuildCentral/rebuildDetail(走完整渲染必重绘, 兼顾 syncSystemTheme 异步切暗时序); rebuildDetail 也按 vtkBackground 设背景 - 主动扫描修掉遗漏: dockManager 分隔条、数据集/文件列表、对象树枝/hint、空状态标题/提示 全走主题 - themed() 公共助手(给需拼接 ADS 样式的 dockManager) --- src/app/Theme.cpp | 5 +++ src/app/Theme.hpp | 4 ++ src/app/login/LoginWindow.cpp | 45 +++++++++++--------- src/app/main.cpp | 67 ++++++++++++++++++------------ src/app/panels/ObjectTreePanel.cpp | 17 ++++---- 5 files changed, 83 insertions(+), 55 deletions(-) diff --git a/src/app/Theme.cpp b/src/app/Theme.cpp index a27b0fb..1f4c24a 100644 --- a/src/app/Theme.cpp +++ b/src/app/Theme.cpp @@ -467,6 +467,11 @@ bool isDarkTheme() return eTheme->getThemeMode() == ElaThemeType::Dark; } +QString themed(const QString& designQss) +{ + return themedQss(designQss, isDarkTheme()); +} + void vtkBackground(double& r, double& g, double& b) { const QColor c = roleColor(isDarkTheme(), ElaThemeType::WindowBase); diff --git a/src/app/Theme.hpp b/src/app/Theme.hpp index 3fa7ab7..a4c4e08 100644 --- a/src/app/Theme.hpp +++ b/src/app/Theme.hpp @@ -101,4 +101,8 @@ void vtkBackground(double& r, double& g, double& b); // (设计稿里用浅色令牌 #1F2A3D/#FFFFFF/#2D6CB5… 书写即可,与全局 QSS 同一套角色映射)。 void applyThemedStyleSheet(QWidget* w, const QString& designQss); +// 把一段「浅色设计稿 QSS」按当前 ElaTheme 配色着色后返回(供需要拼接/手动 setStyleSheet 的场景, +// 如 ADS dockManager 在其自带样式后追加规则)。不自动随主题切换,调用方需自行在切换时重取。 +QString themed(const QString& designQss); + } // namespace geopro::app diff --git a/src/app/login/LoginWindow.cpp b/src/app/login/LoginWindow.cpp index 0badd6f..fbd43ae 100644 --- a/src/app/login/LoginWindow.cpp +++ b/src/app/login/LoginWindow.cpp @@ -91,21 +91,24 @@ LoginWindow::LoginWindow(geopro::net::AuthService& auth, QWidget* parent) // 仅外观:登录窗自带样式(沿用全局主题令牌,保证一脉相承)。 // QLineEdit 在所有状态都显式白底深字 + 边框,避免失焦时取调色板默认色与背景相近不可读。 // 字号引用 Theme 排版令牌:品牌名=display(24)、副标题/字段标签=caption(12)。 - setStyleSheet(QStringLiteral( - "QDialog { background: #F4F6FA; }" - "#headerBand {" - " background: qlineargradient(x1:0, y1:0, x2:1, y2:1," - " stop:0 #2D6CB5, stop:1 #234F87); }" - "#brandTitle { color: #FFFFFF; font-size: %1px; font-weight: %2; }" - "#brandSubtitle { color: rgba(255,255,255,0.82); font-size: %3px; }" - "#fieldLabel { color: #5A6B85; font-size: %4px; font-weight: %5; }" - // 输入框已 Ela 化(ElaLineEdit 自绘 Fluent + 自动明暗),不再写 QLineEdit QSS。 - "#captchaImg { border: 1px solid #C7D2E0; border-radius: 8px; background: #EEF2FB; }") - .arg(type::kDisplay) - .arg(type::kWeightBold) - .arg(type::kCaption) - .arg(type::kCaption) - .arg(type::kWeightSemibold)); + // 登录窗整体随 ElaTheme 着色(与 Ela 化的输入/按钮一致,避免暗系统下浅窗+暗控件割裂)。 + // 品牌带文字用 white 关键字(不入角色映射→恒为白),保证落在蓝色横幅上始终可读。 + geopro::app::applyThemedStyleSheet( + this, QStringLiteral( + "QDialog { background: #F4F6FA; }" + "#headerBand {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1," + " stop:0 #2D6CB5, stop:1 #234F87); }" + "#brandTitle { color: white; font-size: %1px; font-weight: %2; }" + "#brandSubtitle { color: rgba(255,255,255,0.82); font-size: %3px; }" + "#fieldLabel { color: #5A6B85; font-size: %4px; font-weight: %5; }" + // 输入框已 Ela 化(ElaLineEdit 自绘 Fluent + 自动明暗),不再写 QLineEdit QSS。 + "#captchaImg { border: 1px solid #C7D2E0; border-radius: 8px; background: #EEF2FB; }") + .arg(type::kDisplay) + .arg(type::kWeightBold) + .arg(type::kCaption) + .arg(type::kCaption) + .arg(type::kWeightSemibold)); auto* root = new QVBoxLayout(this); root->setContentsMargins(0, 0, 0, 0); @@ -179,9 +182,11 @@ LoginWindow::LoginWindow(geopro::net::AuthService& auth, QWidget* parent) refreshBtn_ = new QPushButton(QStringLiteral("看不清?换一张"), body); refreshBtn_->setFlat(true); refreshBtn_->setCursor(Qt::PointingHandCursor); - refreshBtn_->setStyleSheet(QStringLiteral( - "QPushButton { color: #2D6CB5; border: none; background: transparent; padding: 2px 0; }" - "QPushButton:hover { color: #234F87; text-decoration: underline; }")); + geopro::app::applyThemedStyleSheet( + refreshBtn_, + QStringLiteral( + "QPushButton { color: #2D6CB5; border: none; background: transparent; padding: 2px 0; }" + "QPushButton:hover { color: #234F87; text-decoration: underline; }")); refreshRow->addWidget(refreshBtn_); form->addLayout(refreshRow); @@ -192,8 +197,8 @@ LoginWindow::LoginWindow(geopro::net::AuthService& auth, QWidget* parent) // 错误提示:固定占位高度,避免出现时整体布局跳动。 errorLabel_ = new QLabel(body); - errorLabel_->setStyleSheet( - QStringLiteral("color: #C0392B; font-size: %1px;").arg(type::kCaption)); + geopro::app::applyThemedStyleSheet( + errorLabel_, QStringLiteral("color: #C0392B; font-size: %1px;").arg(type::kCaption)); errorLabel_->setWordWrap(true); errorLabel_->setMinimumHeight(18); form->addWidget(errorLabel_); diff --git a/src/app/main.cpp b/src/app/main.cpp index 5117475..2e8fb92 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -289,12 +289,19 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re window.setCentralWidget(dockManager); // 覆盖 ADS 自带分隔条样式:其 default.css 用 palette(dark) 把面板间分隔画成深灰粗线, - // 且设在管理器自身、选择器更具体(优先级高于全局主题)。这里在其后追加同选择器规则覆盖为极淡分隔。 - dockManager->setStyleSheet( - dockManager->styleSheet() + - QStringLiteral( - "ads--CDockContainerWidget ads--CDockSplitter::handle { background: #EAEEF4; }" - "ads--CDockContainerWidget ads--CDockSplitter::handle:hover { background: #C7D2E0; }")); + // 且设在管理器自身、选择器更具体(优先级高于全局主题)。在其后追加同选择器、按主题着色的极淡分隔覆盖。 + // 捕获 ADS 基样式一次(避免每次切换重复追加而无限增长),切主题时用 base + 重新着色的覆盖。 + const QString dockBaseQss = dockManager->styleSheet(); + auto applyDockSplitter = [dockManager, dockBaseQss]() { + dockManager->setStyleSheet( + dockBaseQss + + geopro::app::themed(QStringLiteral( + "ads--CDockContainerWidget ads--CDockSplitter::handle { background: #EAEEF4; }" + "ads--CDockContainerWidget ads--CDockSplitter::handle:hover { background: #C7D2E0; }"))); + }; + applyDockSplitter(); + QObject::connect(eTheme, &ElaTheme::themeModeChanged, dockManager, + [applyDockSplitter](ElaThemeType::ThemeMode) { applyDockSplitter(); }); // 面板包装:内容顶部加自绘表头(图标+标题+操作按钮),ADS 自带标题栏随后隐藏, // 从而让面板表头与原型完全一致。返回 [表头 + 内容] 容器供 setWidget。 @@ -397,16 +404,17 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re auto* esTitle = new QLabel(QStringLiteral("选择左侧数据集开始分析"), emptyState); esTitle->setAlignment(Qt::AlignCenter); - esTitle->setStyleSheet(QStringLiteral("color:#5A6B85; font-size:%1px; font-weight:%2;") - .arg(geopro::app::type::kHeading) - .arg(geopro::app::type::kWeightSemibold)); + geopro::app::applyThemedStyleSheet( + esTitle, QStringLiteral("color:#5A6B85; font-size:%1px; font-weight:%2;") + .arg(geopro::app::type::kHeading) + .arg(geopro::app::type::kWeightSemibold)); auto* esHint = new QLabel(QStringLiteral("单击左侧采集批次,查看反演剖面与异常点\n" "切到「三维视图」可叠加帘面、体素与地形图层"), emptyState); esHint->setAlignment(Qt::AlignCenter); - esHint->setStyleSheet( - QStringLiteral("color:#8A93A3; font-size:%1px;").arg(geopro::app::type::kBody)); + geopro::app::applyThemedStyleSheet( + esHint, QStringLiteral("color:#8A93A3; font-size:%1px;").arg(geopro::app::type::kBody)); esLay->addWidget(esIcon); esLay->addWidget(esTitle); @@ -443,17 +451,8 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re detailRenderWindow->AddRenderer(detailRenderer); vtkRenderer* detailRendererPtr = detailRenderer.Get(); vtkGenericOpenGLRenderWindow* detailRenderWindowPtr = detailRenderWindow.Get(); - - // VTK 背景随主题切换:ElaTheme 明/暗切换时,中央+详情渲染器重设底色并刷新。 - QObject::connect(eTheme, &ElaTheme::themeModeChanged, detailWidget, - [rendererPtr, renderWindowPtr, detailRendererPtr, detailRenderWindowPtr]() { - double r, g, b; - geopro::app::vtkBackground(r, g, b); - rendererPtr->SetBackground(r, g, b); - renderWindowPtr->Render(); - detailRendererPtr->SetBackground(r, g, b); - detailRenderWindowPtr->Render(); - }); + // 注:VTK 背景随主题切换的连接放在 rebuildCentral/rebuildDetail 定义之后(直接重跑它们, + // 走完整渲染路径必重绘,比手动 SetBackground+Render 稳)。 // 数据详情容器:顶部「反演剖面/原数据」工具条 + 下方 QVTK 小视图。 auto* detailContainer = new QWidget(); @@ -504,15 +503,16 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re // 左下 dock:数据真实显示栏(选中测线后列其采集批次=数据集;tab 数据/文件)。 auto* datasetTabs = new QTabWidget(); auto* datasetList = new QListWidget(); - // 简洁分割:去隔行变色,改为 item 间极淡分割线 + 内边距 + hover/选中反馈(专业、不误导)。 - datasetList->setStyleSheet(QStringLiteral( + // 简洁分割:去隔行变色,改为 item 间极淡分割线 + 内边距 + hover/选中反馈(专业、不误导)。随主题着色。 + const QString kListQss = QStringLiteral( "QListWidget{ background:#FFFFFF; border:none; outline:none; }" "QListWidget::item{ padding:9px 12px; border-bottom:1px solid #EEF1F5; color:#1F2A3D; }" - "QListWidget::item:hover{ background:#F5F8FD; }" - "QListWidget::item:selected{ background:#EAF1FB; color:#1F2A3D; }")); + "QListWidget::item:hover{ background:#EEF3FB; }" + "QListWidget::item:selected{ background:#EAF1FB; color:#1F2A3D; }"); + geopro::app::applyThemedStyleSheet(datasetList, kListQss); datasetTabs->addTab(datasetList, QStringLiteral("数据")); auto* fileList = new QListWidget(); - fileList->setStyleSheet(datasetList->styleSheet()); // 与数据页签同款简洁分割 + geopro::app::applyThemedStyleSheet(fileList, kListQss); // 与数据页签同款简洁分割 datasetTabs->addTab(fileList, QStringLiteral("文件")); auto* datasetDock = new ads::CDockWidget(QStringLiteral("数据真实显示栏")); auto* datasetBox = wrapWithHeader( @@ -608,6 +608,11 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re fromCam->DeepCopy(detailRendererPtr->GetActiveCamera()); detailRendererPtr->RemoveAllViewProps(); + { // 背景随主题 + double r, g, b; + geopro::app::vtkBackground(r, g, b); + detailRendererPtr->SetBackground(r, g, b); + } if (currentDsId->isEmpty()) { // 未选数据集:清空即可 *prevDsId = *currentDsId; detailRenderWindowPtr->Render(); @@ -822,6 +827,14 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re // ── 启动:建立一次空背景中央视图(真实 sections 数据由下一轮接入)。 rebuildCentral(); + // VTK 背景随主题切换:直接重跑 rebuildCentral/rebuildDetail(走完整渲染路径、末尾必 Render, + // 比手动 SetBackground+Render 稳;兼顾 syncSystemTheme 异步切暗的时序)。 + QObject::connect(eTheme, &ElaTheme::themeModeChanged, &window, + [rebuildCentral, rebuildDetail]() { + rebuildCentral(); + rebuildDetail(); + }); + // 顶部应用区(静态视觉壳,对齐原型):上=菜单栏(视图/项目管理/业务工具/设备), // 下=工具条(工作空间切换 + 项目 + 帮助/通知/设置 + 用户)。纵向堆叠后挂到主窗口顶部。 geopro::app::TopBar* topBar = nullptr; diff --git a/src/app/panels/ObjectTreePanel.cpp b/src/app/panels/ObjectTreePanel.cpp index 2e330d4..66c1ea7 100644 --- a/src/app/panels/ObjectTreePanel.cpp +++ b/src/app/panels/ObjectTreePanel.cpp @@ -8,6 +8,7 @@ #include #include "Glyphs.hpp" +#include "Theme.hpp" #include "dto/NavDto.hpp" namespace geopro::app { @@ -40,19 +41,19 @@ ObjectTreePanel::ObjectTreePanel(QWidget* parent) : QWidget(parent) { { const QString openArrow = writeChevronIcon(true, QColor("#8A93A3")); const QString closedArrow = writeChevronIcon(false, QColor("#8A93A3")); - tree_->setStyleSheet( - QStringLiteral("QTreeView::branch { background: #FFFFFF; }" - "QTreeView::branch:has-children:!has-siblings:closed," - "QTreeView::branch:closed:has-children:has-siblings { image: url(%1); }" - "QTreeView::branch:open:has-children:!has-siblings," - "QTreeView::branch:open:has-children:has-siblings { image: url(%2); }") - .arg(closedArrow, openArrow)); + geopro::app::applyThemedStyleSheet( + tree_, QStringLiteral("QTreeView::branch { background: #FFFFFF; }" + "QTreeView::branch:has-children:!has-siblings:closed," + "QTreeView::branch:closed:has-children:has-siblings { image: url(%1); }" + "QTreeView::branch:open:has-children:!has-siblings," + "QTreeView::branch:open:has-children:has-siblings { image: url(%2); }") + .arg(closedArrow, openArrow)); } lay->addWidget(tree_, 1); hint_ = new QLabel(QStringLiteral("正在加载对象…"), this); hint_->setAlignment(Qt::AlignCenter); - hint_->setStyleSheet(QStringLiteral("color:#9AA6B6; padding:16px;")); + geopro::app::applyThemedStyleSheet(hint_, QStringLiteral("color:#9AA6B6; padding:16px;")); hint_->setVisible(false); lay->addWidget(hint_);