feat(vtk): 列表单击已选中数据可取消选中(恢复全景轴)

在 CategorySection 段体树上安装 viewport 事件过滤器,于左键按下瞬间
(默认改选前) 记录被按行及其选中态;itemClicked(释放)时若该行按下前已选中
且本次未点勾选框,则 clearSelection() 直发 datasetSelected("") → 上层
恢复全景轴、丢贴合轴。点勾选框(切渲染)与容器行不触发取消。双击仍激活:
首击可能 toggle 掉选中,itemDoubleClicked 补回选中,终态=选中+贴合轴+详情。
不影响全列互斥(Fix A)、防环、右键菜单与切片/异常高亮。
This commit is contained in:
gaozheng 2026-07-01 12:22:28 +08:00
parent e1a10a1a73
commit 8b32566351
2 changed files with 40 additions and 0 deletions

View File

@ -8,6 +8,7 @@
#include <QHBoxLayout>
#include <QLabel>
#include <QMenu>
#include <QMouseEvent>
#include <QPoint>
#include <QPushButton>
#include <QSet>
@ -144,18 +145,35 @@ CategorySection::CategorySection(const geopro::data::CategoryDescriptor& desc,
list_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
list_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
applyDatasetCardDelegate(list_);
list_->viewport()->installEventFilter(this); // 捕获按下瞬间选中态(默认改选前),供单击已选行 toggle 取消
connect(list_, &QTreeWidget::itemChanged, this, [this](QTreeWidgetItem* it, int) {
// 用户点勾选框会在按下→释放间先发 itemChanged标记本次按下改动了勾选框itemClicked 据此不取消选中
// (点勾选框只切渲染,不应连带取消该行选中/丢贴合轴)。程序化改勾选均走 SignalBlocker不到此处。
if (it && it == pressedItem_) checkToggledThisPress_ = true;
// 异常行复选框 = 该异常显隐(异常不进渲染勾选集,单独走 anomalyVisibilityChanged → setAnomalyVisible
if (it && it->data(0, kDsDdCodeRole).toString() == QStringLiteral("dd_anomaly"))
emit anomalyVisibilityChanged(it->data(0, kDsIdRole).toString(),
it->checkState(0) == Qt::Checked);
emitChecked();
});
// 单击已选中的数据行 → 取消选中toggle-offitemClicked 于释放时触发,此时选中态已落定;
// 仅当「按下瞬间该行已选中」且「本次未点勾选框」才取消。取消走 list_->clearSelection()(非成员
// clearSelection后者阻断信号→ 直发 itemSelectionChanged(空) → datasetSelected("") → 恢复全景轴、丢贴合轴。
// 双击仍可激活:首次释放虽可能 toggle 掉选中,随后 DblClick 会重新选中该行并发 datasetActivatedfit+详情)。
connect(list_, &QTreeWidget::itemClicked, this, [this](QTreeWidgetItem* it, int) {
if (!it || it != pressedItem_ || !pressedSelected_ || checkToggledThisPress_) return;
if (it->data(0, kDsDdCodeRole).toString() == QStringLiteral("container")) return; // 容器行不参与选中
pressedSelected_ = false; // 防重入
list_->clearSelection(); // 发空 itemSelectionChanged → datasetSelected("") → 上层恢复全景轴
});
connect(list_, &QTreeWidget::itemDoubleClicked, this, [this](QTreeWidgetItem* it, int) {
const QString id = it->data(0, kDsIdRole).toString();
if (id.isEmpty()) return;
// 双击=适配相机到该 ds 子树盒 + 联动中下方图表详情页(无图表页类型静默,见 main.cpp T4 接线)。
// 属性弹窗改由右键「详情」触发detailRequested双击不再弹属性框决策6三维体只适配、静默
// 双击首击的 itemClicked 可能已把「本已选中」的该行 toggle 取消(见下方 toggle 逻辑);此处补回选中,
// 使双击终态 = 选中+贴合轴+详情一致(!isSelected 仅在被 toggle 掉时成立,正常双击未选行首击已选中→跳过)。
if (!it->isSelected()) list_->setCurrentItem(it);
emit datasetActivated(id, it->data(0, kDsDdCodeRole).toString(), it->data(0, kDsNameRole).toString());
});
// 树选中任意数据行 → datasetSelected各类型段通用驱动该 ds 子树贴合坐标轴spec §3.2
@ -185,6 +203,20 @@ CategorySection::CategorySection(const geopro::data::CategoryDescriptor& desc,
});
}
bool CategorySection::eventFilter(QObject* obj, QEvent* ev) {
// 段体树 viewport 左键按下:在 QTreeWidget 默认处理改选之前,记录被按行及其「按下瞬间是否已选中」,
// 并清本次「勾选框改动」标记。itemClicked释放据此判定已选中且未点勾选框 → toggle 取消选中。
if (list_ && obj == list_->viewport() && ev->type() == QEvent::MouseButtonPress) {
auto* me = static_cast<QMouseEvent*>(ev);
if (me->button() == Qt::LeftButton) {
pressedItem_ = list_->itemAt(me->position().toPoint());
pressedSelected_ = pressedItem_ && pressedItem_->isSelected();
checkToggledThisPress_ = false;
}
}
return QWidget::eventFilter(obj, ev);
}
bool CategorySection::isExpanded() const { return header_ && header_->isChecked(); }
void CategorySection::ensureExpanded() {

View File

@ -54,6 +54,10 @@ public:
QStringList subtreeDsIds(const QString& dsId) const;
bool hasRenderableRows() const; // 段体是否含可渲染数据行(非 container 容器节点),供单列动态显隐
protected:
// 段体树 viewport 事件过滤:在默认处理改选之前记录「按下瞬间该行是否已选中」,供单击已选行的 toggle 取消判定。
bool eventFilter(QObject* obj, QEvent* ev) override;
signals:
void checkedDatasetsChanged(const QStringList& dsIds); // 数据行勾选=渲染
void collapsedChanged(); // 折叠/展开切换 → 外层 CategoryAnalysisTab 重排各段 stretch
@ -106,6 +110,10 @@ private:
int lastBasemapOpacity_ = 50; // 上次底图透明度0100重开 popup 回显;默认 50
QTimer* basemapOpacityTimer_ = nullptr; // 底图透明度滑块发射防抖(透明度改动会触发瓦片重铺,仍需防抖)
double pendingBasemapOpacity_ = 0.5; // 防抖待发的底图透明度[0,1](定时器到点发射 basemapOpacityChanged
// 单击已选行取消选中toggle-offeventFilter 于按下瞬间(默认改选前)记录被按行及其选中态itemClicked 据此取消。
QTreeWidgetItem* pressedItem_ = nullptr; // 本次左键按下的行itemAt(press),与 itemClicked 的行比对)
bool pressedSelected_ = false; // 按下瞬间该行是否已选中true 且非勾选框点击时,单击取消选中)
bool checkToggledThisPress_ = false; // 本次按下是否切换了勾选框(点勾选框只改渲染,不取消选中)
};
} // namespace geopro::app