From 09a48d846b04b9af91bf476c7335b7cf5c7e0c4e Mon Sep 17 00:00:00 2001 From: gaozheng Date: Thu, 25 Jun 2026 18:46:06 +0800 Subject: [PATCH] =?UTF-8?q?fix(ui):=20=E6=A0=8F=E4=BD=8D=E5=8B=BE=E9=80=89?= =?UTF-8?q?=E5=A2=9E=E9=87=8F=E4=BF=9D=E7=95=99=20+=20tab=E5=8E=BB?= =?UTF-8?q?=E7=AE=AD=E5=A4=B4=20+=20=E7=BC=A9=E8=BF=9B=20+=20=E6=BB=91?= =?UTF-8?q?=E5=9D=97=E8=B7=B3=E4=BD=8D=20+=20=E6=B8=85=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 栏位状态增量(最关键):CategorySection::rebuildList 记住已勾选 ds、重建后复原;之前每次刷新 (勾选对象/建体/存切片/建异常都触发)清空全部勾选→渲染被重置。复原后 emitChecked 上抛同集, 控制器据 diff 增量保留已渲染图元 - #1 tab 左右滚动箭头:上轮宽度算法没扣 padding 致溢出。扣开销(~42)稍欠宽 + setUsesScrollButtons(false) 兜底 - #6 缩进:容器文本左缘对齐子级复选框列起点(pad 12,非整列36),「容器→带框子级」缩进=树级(14), 与「带框→带框」一致,且名称仍紧邻展开图标(无 #2 大留白) - 5.5 滑块点轨道跳位:ClickJumpSlider 用 QStyle::sliderValueFromPosition 点哪跳哪(点手柄正常拖动) - 日志 201× QFont pointSize<=0(-1) 警告:ObjectRowDelegate 去掉多余 setPointSizeF(-1)(setPixelSize 直接生效) 构建:app 链接通过 --- src/app/AxesSettingsPanel.cpp | 31 +++++++++++++++++++++- src/app/panels/DatasetListPanel.cpp | 8 +++++- src/app/panels/ObjectTreePanel.cpp | 4 +-- src/app/panels/columns/CategorySection.cpp | 12 +++++++-- src/app/panels/columns/ColumnDrawer.cpp | 5 +++- 5 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/app/AxesSettingsPanel.cpp b/src/app/AxesSettingsPanel.cpp index 9d3e0ba..2ba1294 100644 --- a/src/app/AxesSettingsPanel.cpp +++ b/src/app/AxesSettingsPanel.cpp @@ -7,14 +7,43 @@ #include #include #include +#include #include #include +#include +#include #include #include "Theme.hpp" namespace geopro::app { +namespace { +// 点击轨道直接定位到点击处(默认 QSlider 点轨道只按 pageStep 步进;用户要求点哪跳哪)。 +class ClickJumpSlider : public QSlider { +public: + using QSlider::QSlider; + +protected: + void mousePressEvent(QMouseEvent* e) override { + if (e->button() == Qt::LeftButton && orientation() == Qt::Horizontal) { + QStyleOptionSlider opt; + initStyleOption(&opt); + const QRect handle = + style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); + if (!handle.contains(e->pos())) { // 点在轨道(非手柄) → 跳到点击位置 + const int span = width() - handle.width(); + const int x = e->pos().x() - handle.width() / 2; + setValue(QStyle::sliderValueFromPosition(minimum(), maximum(), x, span)); + e->accept(); + return; + } + } + QSlider::mousePressEvent(e); // 点手柄 → 正常拖动 + } +}; +} // namespace + AxesSettingsPanel::AxesSettingsPanel(QWidget* parent) : QFrame(parent) { setFrameShape(QFrame::StyledPanel); applyTokenizedStyleSheet( @@ -64,7 +93,7 @@ AxesSettingsPanel::AxesSettingsPanel(QWidget* parent) : QFrame(parent) { auto* scaleLbl = new QLabel(QStringLiteral("放大系数"), this); scaleLbl->setStyleSheet(QStringLiteral("border:none;")); scaleRow->addWidget(scaleLbl); - scaleSlider_ = new QSlider(Qt::Horizontal, this); + scaleSlider_ = new ClickJumpSlider(Qt::Horizontal, this); scaleSlider_->setMinimum(1); scaleSlider_->setMaximum(10); scaleSlider_->setValue(1); diff --git a/src/app/panels/DatasetListPanel.cpp b/src/app/panels/DatasetListPanel.cpp index a97bd96..b396344 100644 --- a/src/app/panels/DatasetListPanel.cpp +++ b/src/app/panels/DatasetListPanel.cpp @@ -84,10 +84,11 @@ public: // 可勾选项:左侧画复选框(用当前 style 的指示器),文本整体右移。容器节点(项目/GS/TM)不画 // 复选框、名称紧跟展开图标(左留白小,与对象树容器一致;勿为对齐子级而预留空复选框列, // 否则容器名与展开图标间出现大段空白,见用户 #2 反馈)。 + const int box = 16; int textLeftPad = 6; const bool checkable = (idx.flags() & Qt::ItemIsUserCheckable); + const bool isContainer = idx.data(kDsDdCodeRole).toString() == QStringLiteral("container"); if (checkable) { - const int box = 16; QRect checkRect(r.left() + 12, r.top() + (r.height() - box) / 2, box, box); const auto cs = static_cast(idx.data(Qt::CheckStateRole).toInt()); QStyleOptionViewItem o(opt); @@ -98,6 +99,11 @@ public: QStyle* st = w ? w->style() : QApplication::style(); st->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &o, p, w); textLeftPad = 12 + box + 8; // 复选框右侧留白后再放文本 + } else if (isContainer) { + // 容器文本左缘对齐子级复选框的左缘(r.left()+12)——使「容器→带框子级」的视觉缩进 = 一个树级 + // (14px),与「带框父→带框子」一致,消除带框子级相对容器缩进过大(用户 #6)。只 +12(非整列宽), + // 故名称仍紧邻展开图标、无 #2 的大留白。 + textLeftPad = 12; } QString title = disp, meta; diff --git a/src/app/panels/ObjectTreePanel.cpp b/src/app/panels/ObjectTreePanel.cpp index c66911d..f260c03 100644 --- a/src/app/panels/ObjectTreePanel.cpp +++ b/src/app/panels/ObjectTreePanel.cpp @@ -86,8 +86,8 @@ public: const int count = idx.data(kRoleChildCount).toInt(); if (count > 0) { QFont f = opt.font; - f.setPointSizeF(-1); - f.setPixelSize(scaledPx(type::kCaption)); + f.setPixelSize(scaledPx(type::kCaption)); // setPixelSize 直接生效,无需先 setPointSizeF(-1) + // (-1 会触发 QFont::setPointSizeF 警告刷屏日志) f.setWeight(QFont::Normal); painter->setFont(f); painter->setPen(tokenColor("text/tertiary")); diff --git a/src/app/panels/columns/CategorySection.cpp b/src/app/panels/columns/CategorySection.cpp index 7ca6a0b..c76e765 100644 --- a/src/app/panels/columns/CategorySection.cpp +++ b/src/app/panels/columns/CategorySection.cpp @@ -169,6 +169,13 @@ bool CategorySection::passesFilters(const DsRow& row) const { } void CategorySection::rebuildList() { + // 增量保留:记住当前已勾选的 ds,重建后复原(仍存在的项保持勾选)。否则每次刷新(勾选对象/建体/ + // 存切片/建异常都会触发)清空全部勾选 → 渲染被重置,体验极差(用户反馈:必须增量更新)。 + std::set wasChecked; + for (QTreeWidgetItemIterator it(list_); *it; ++it) + if ((*it)->checkState(0) == Qt::Checked) + wasChecked.insert((*it)->data(0, kDsIdRole).toString().toStdString()); + std::vector filtered; filtered.reserve(rows_.size()); for (const auto& r : rows_) @@ -219,7 +226,8 @@ void CategorySection::rebuildList() { continue; } (*it)->setFlags((*it)->flags() | Qt::ItemIsUserCheckable); - (*it)->setCheckState(0, Qt::Unchecked); + const std::string id = (*it)->data(0, kDsIdRole).toString().toStdString(); + (*it)->setCheckState(0, wasChecked.count(id) ? Qt::Checked : Qt::Unchecked); // 复原勾选 } } list_->expandAll(); // 展开容器层级(项目根/GS/TM),让体/切片/异常可见 @@ -230,7 +238,7 @@ void CategorySection::rebuildList() { if (!(*hit)->isHidden()) contentH += (*hit)->text(0).contains(QLatin1Char('\n')) ? 52 : 30; list_->setMinimumHeight(contentH); - emitChecked(); // 重建后必为空选,清掉上次渲染勾选 + emitChecked(); // 上抛复原后的勾选集(保持渲染,不再清空 → 控制器据 diff 增量保留已渲染图元) } QStringList CategorySection::checkedDsIds() const { diff --git a/src/app/panels/columns/ColumnDrawer.cpp b/src/app/panels/columns/ColumnDrawer.cpp index 640eb5b..13dd8ad 100644 --- a/src/app/panels/columns/ColumnDrawer.cpp +++ b/src/app/panels/columns/ColumnDrawer.cpp @@ -24,6 +24,7 @@ ColumnDrawer::ColumnDrawer(QWidget* parent, geopro::data::DatasetFieldDictionary body_ = tabs; tabs->addTab(analysisTab_, QStringLiteral("三维分析")); tabs->addTab(col2D_, QStringLiteral("二维分析")); + tabs->tabBar()->setUsesScrollButtons(false); // 永不出左右滚动箭头(两 tab 必能平铺) // 折叠按钮:固定宽 18px,垂直拉伸。 // 用 SVG 图标(makeGlyph)而非 ◀/▶ 文字——三角符(U+25C0/25B6)不在 YaHei,作按钮文字会触发 @@ -61,7 +62,9 @@ void ColumnDrawer::resizeEvent(QResizeEvent* e) if (auto* tabs = qobject_cast(body_)) { const int n = tabs->count(); if (n > 0 && tabs->width() > 0) { - const int w = std::max(40, tabs->width() / n - 6); // 减 margin-right(4)余量 + // 每 tab 内容宽 = 总宽/n - 每 tab 非内容开销(全局 QSS padding 8+16+16=… 约 32 + margin 4)。 + // 稍欠一点宽避免溢出(溢出会触发滚动箭头);setUsesScrollButtons(false) 再兜底。 + const int w = std::max(40, tabs->width() / n - 42); tabs->tabBar()->setStyleSheet(QStringLiteral("QTabBar::tab{width:%1px;}").arg(w)); } }