feat(vtk): 列表单击已选中数据可取消选中(恢复全景轴)
在 CategorySection 段体树上安装 viewport 事件过滤器,于左键按下瞬间
(默认改选前) 记录被按行及其选中态;itemClicked(释放)时若该行按下前已选中
且本次未点勾选框,则 clearSelection() 直发 datasetSelected("") → 上层
恢复全景轴、丢贴合轴。点勾选框(切渲染)与容器行不触发取消。双击仍激活:
首击可能 toggle 掉选中,itemDoubleClicked 补回选中,终态=选中+贴合轴+详情。
不影响全列互斥(Fix A)、防环、右键菜单与切片/异常高亮。
This commit is contained in:
parent
e1a10a1a73
commit
8b32566351
|
|
@ -8,6 +8,7 @@
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
#include <QMouseEvent>
|
||||||
#include <QPoint>
|
#include <QPoint>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
|
@ -144,18 +145,35 @@ CategorySection::CategorySection(const geopro::data::CategoryDescriptor& desc,
|
||||||
list_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
list_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
list_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
list_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
applyDatasetCardDelegate(list_);
|
applyDatasetCardDelegate(list_);
|
||||||
|
list_->viewport()->installEventFilter(this); // 捕获按下瞬间选中态(默认改选前),供单击已选行 toggle 取消
|
||||||
connect(list_, &QTreeWidget::itemChanged, this, [this](QTreeWidgetItem* it, int) {
|
connect(list_, &QTreeWidget::itemChanged, this, [this](QTreeWidgetItem* it, int) {
|
||||||
|
// 用户点勾选框会在按下→释放间先发 itemChanged:标记本次按下改动了勾选框,itemClicked 据此不取消选中
|
||||||
|
// (点勾选框只切渲染,不应连带取消该行选中/丢贴合轴)。程序化改勾选均走 SignalBlocker,不到此处。
|
||||||
|
if (it && it == pressedItem_) checkToggledThisPress_ = true;
|
||||||
// 异常行复选框 = 该异常显隐(异常不进渲染勾选集,单独走 anomalyVisibilityChanged → setAnomalyVisible)。
|
// 异常行复选框 = 该异常显隐(异常不进渲染勾选集,单独走 anomalyVisibilityChanged → setAnomalyVisible)。
|
||||||
if (it && it->data(0, kDsDdCodeRole).toString() == QStringLiteral("dd_anomaly"))
|
if (it && it->data(0, kDsDdCodeRole).toString() == QStringLiteral("dd_anomaly"))
|
||||||
emit anomalyVisibilityChanged(it->data(0, kDsIdRole).toString(),
|
emit anomalyVisibilityChanged(it->data(0, kDsIdRole).toString(),
|
||||||
it->checkState(0) == Qt::Checked);
|
it->checkState(0) == Qt::Checked);
|
||||||
emitChecked();
|
emitChecked();
|
||||||
});
|
});
|
||||||
|
// 单击已选中的数据行 → 取消选中(toggle-off):itemClicked 于释放时触发,此时选中态已落定;
|
||||||
|
// 仅当「按下瞬间该行已选中」且「本次未点勾选框」才取消。取消走 list_->clearSelection()(非成员
|
||||||
|
// clearSelection,后者阻断信号)→ 直发 itemSelectionChanged(空) → datasetSelected("") → 恢复全景轴、丢贴合轴。
|
||||||
|
// 双击仍可激活:首次释放虽可能 toggle 掉选中,随后 DblClick 会重新选中该行并发 datasetActivated(fit+详情)。
|
||||||
|
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) {
|
connect(list_, &QTreeWidget::itemDoubleClicked, this, [this](QTreeWidgetItem* it, int) {
|
||||||
const QString id = it->data(0, kDsIdRole).toString();
|
const QString id = it->data(0, kDsIdRole).toString();
|
||||||
if (id.isEmpty()) return;
|
if (id.isEmpty()) return;
|
||||||
// 双击=适配相机到该 ds 子树盒 + 联动中下方图表详情页(无图表页类型静默,见 main.cpp T4 接线)。
|
// 双击=适配相机到该 ds 子树盒 + 联动中下方图表详情页(无图表页类型静默,见 main.cpp T4 接线)。
|
||||||
// 属性弹窗改由右键「详情」触发(detailRequested),双击不再弹属性框(决策6:三维体只适配、静默)。
|
// 属性弹窗改由右键「详情」触发(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());
|
emit datasetActivated(id, it->data(0, kDsDdCodeRole).toString(), it->data(0, kDsNameRole).toString());
|
||||||
});
|
});
|
||||||
// 树选中任意数据行 → datasetSelected(各类型段通用):驱动该 ds 子树贴合坐标轴(spec §3.2),
|
// 树选中任意数据行 → 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(); }
|
bool CategorySection::isExpanded() const { return header_ && header_->isChecked(); }
|
||||||
|
|
||||||
void CategorySection::ensureExpanded() {
|
void CategorySection::ensureExpanded() {
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,10 @@ public:
|
||||||
QStringList subtreeDsIds(const QString& dsId) const;
|
QStringList subtreeDsIds(const QString& dsId) const;
|
||||||
bool hasRenderableRows() const; // 段体是否含可渲染数据行(非 container 容器节点),供单列动态显隐
|
bool hasRenderableRows() const; // 段体是否含可渲染数据行(非 container 容器节点),供单列动态显隐
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// 段体树 viewport 事件过滤:在默认处理改选之前记录「按下瞬间该行是否已选中」,供单击已选行的 toggle 取消判定。
|
||||||
|
bool eventFilter(QObject* obj, QEvent* ev) override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void checkedDatasetsChanged(const QStringList& dsIds); // 数据行勾选=渲染
|
void checkedDatasetsChanged(const QStringList& dsIds); // 数据行勾选=渲染
|
||||||
void collapsedChanged(); // 折叠/展开切换 → 外层 CategoryAnalysisTab 重排各段 stretch
|
void collapsedChanged(); // 折叠/展开切换 → 外层 CategoryAnalysisTab 重排各段 stretch
|
||||||
|
|
@ -106,6 +110,10 @@ private:
|
||||||
int lastBasemapOpacity_ = 50; // 上次底图透明度(0–100,重开 popup 回显;默认 50)
|
int lastBasemapOpacity_ = 50; // 上次底图透明度(0–100,重开 popup 回显;默认 50)
|
||||||
QTimer* basemapOpacityTimer_ = nullptr; // 底图透明度滑块发射防抖(透明度改动会触发瓦片重铺,仍需防抖)
|
QTimer* basemapOpacityTimer_ = nullptr; // 底图透明度滑块发射防抖(透明度改动会触发瓦片重铺,仍需防抖)
|
||||||
double pendingBasemapOpacity_ = 0.5; // 防抖待发的底图透明度[0,1](定时器到点发射 basemapOpacityChanged)
|
double pendingBasemapOpacity_ = 0.5; // 防抖待发的底图透明度[0,1](定时器到点发射 basemapOpacityChanged)
|
||||||
|
// 单击已选行取消选中(toggle-off):eventFilter 于按下瞬间(默认改选前)记录被按行及其选中态;itemClicked 据此取消。
|
||||||
|
QTreeWidgetItem* pressedItem_ = nullptr; // 本次左键按下的行(itemAt(press),与 itemClicked 的行比对)
|
||||||
|
bool pressedSelected_ = false; // 按下瞬间该行是否已选中(true 且非勾选框点击时,单击取消选中)
|
||||||
|
bool checkToggledThisPress_ = false; // 本次按下是否切换了勾选框(点勾选框只改渲染,不取消选中)
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace geopro::app
|
} // namespace geopro::app
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue