fix(vtk): 列表选中全局互斥+任意类型ds选中显子树贴合轴

- 解除 CategorySection itemSelectionChanged→datasetSelected 的 voxel-only 门控,
  各类型段(反演帘面/轨迹/三维体等)选中均发选中信号→显子树贴合坐标轴
- 新增 CategorySection::clearSelection()(QSignalBlocker 下清选,不回发信号)
- CategoryAnalysisTab 选中转发改为跨段互斥:某段选中非空则清其余各段选中,
  全列至多一个 ds 选中;inSelectionSync_ 兜底防重入
- 复用既有 applyFittedAxes/subtreeDsIds/datasetBounds,无平行路径
- voxel 切片/异常高亮、视口点选贴合轴对称、T3 gnomon 均未回归
This commit is contained in:
gaozheng 2026-07-01 11:38:09 +08:00
parent fcabf4c59f
commit 0e449e082d
4 changed files with 34 additions and 11 deletions

View File

@ -68,7 +68,19 @@ CategoryAnalysisTab::CategoryAnalysisTab(geopro::data::DatasetFieldDictionary* d
&CategoryAnalysisTab::sliceExportDatRequested);
connect(sec, &CategorySection::anomalyVisibilityChanged, this,
&CategoryAnalysisTab::anomalyVisibilityChanged);
connect(sec, &CategorySection::datasetSelected, this, &CategoryAnalysisTab::datasetSelected);
// 全列互斥选中:某段选中非空数据行 → 清其余各段选中,保证整列至多一个 ds 选中,
// 避免「电阻率段与三维体段各选一行」的二义贴合轴该听谁。clearSelection 内部 QSignalBlocker
// 阻断,被清段不回发 datasetSelected(空)无环路inSelectionSync_ 为兜底防重入。
connect(sec, &CategorySection::datasetSelected, this,
[this, sec](const QString& dsId, const QString& ddCode) {
if (!dsId.isEmpty() && !inSelectionSync_) {
inSelectionSync_ = true;
for (auto* other : ordered_)
if (other != sec) other->clearSelection();
inSelectionSync_ = false;
}
emit datasetSelected(dsId, ddCode);
});
connect(sec, &CategorySection::planeZChanged, this, &CategoryAnalysisTab::planeZChanged);
connect(sec, &CategorySection::basemapKindChanged, this,
&CategoryAnalysisTab::basemapKindChanged);

View File

@ -77,6 +77,7 @@ private:
QVBoxLayout* col_ = nullptr; // 段堆叠布局(末项=尾部弹簧)
QWidget* placeholder_ = nullptr; // 全空时显示的占位提示(与 scroll_ 同级,互斥显隐)
std::map<std::string, QStringList> checkedBySeg_; // 各段当前勾选(合并成并集)
bool inSelectionSync_ = false; // 跨段互斥清选进行中标记防重入信号环clearSelection 已阻断信号,此为兜底)
};
} // namespace geopro::app

View File

@ -158,19 +158,21 @@ CategorySection::CategorySection(const geopro::data::CategoryDescriptor& desc,
// 属性弹窗改由右键「详情」触发detailRequested双击不再弹属性框决策6三维体只适配、静默
emit datasetActivated(id, it->data(0, kDsDdCodeRole).toString(), it->data(0, kDsNameRole).toString());
});
// 树选中任意数据行 → datasetSelected各类型段通用驱动该 ds 子树贴合坐标轴spec §3.2
// 并由上层 CategoryAnalysisTab 做全列互斥。voxel 段切片/异常的 VTK 高亮由上层据 ddCode 处理,
// 故此信号对所有段发射即可,任意类型选中都能显子树贴合轴(非仅三维体)。
// 空选中(点树空白/清选)→ 发空 datasetSelected上层据此恢复全景轴、清高亮贴合轴取消
connect(list_, &QTreeWidget::itemSelectionChanged, this, [this] {
const auto items = list_->selectedItems();
if (items.isEmpty()) { emit datasetSelected(QString(), QString()); return; }
QTreeWidgetItem* it = items.first();
const QString id = it->data(0, kDsIdRole).toString();
const QString dd = it->data(0, kDsDdCodeRole).toString();
if (!id.isEmpty() && dd != QStringLiteral("container")) emit datasetSelected(id, dd);
});
if (desc_.id == "voxel") { // 仅三维体段提供右键操作菜单(体/切片/异常)
list_->setContextMenuPolicy(Qt::CustomContextMenu);
connect(list_, &QTreeWidget::customContextMenuRequested, this, &CategorySection::showContextMenu);
// 树选中切片/异常 → VTK 高亮联动(正向 list→VTK
connect(list_, &QTreeWidget::itemSelectionChanged, this, [this] {
const auto items = list_->selectedItems();
// 空选中(点树空白/清选)→ 发空 datasetSelected上层据此恢复全景轴、清高亮贴合轴取消spec §3.2)。
if (items.isEmpty()) { emit datasetSelected(QString(), QString()); return; }
QTreeWidgetItem* it = items.first();
const QString id = it->data(0, kDsIdRole).toString();
const QString dd = it->data(0, kDsDdCodeRole).toString();
if (!id.isEmpty() && dd != QStringLiteral("container")) emit datasetSelected(id, dd);
});
}
body->addWidget(list_, 1);
@ -247,6 +249,13 @@ void CategorySection::selectItem(const QString& dsId) {
list_->setCurrentItem(nullptr); // 空 dsId / 未找到 → 清选中
}
void CategorySection::clearSelection() {
if (!list_) return;
const QSignalBlocker block(list_); // 跨段互斥清选:被清段不回发 datasetSelected(空),避免环路/误恢复全景轴
list_->setCurrentItem(nullptr);
list_->clearSelection();
}
void CategorySection::setChecked(const QString& dsId, bool on) {
for (QTreeWidgetItemIterator it(list_); *it; ++it)
if ((*it)->data(0, kDsIdRole).toString() == dsId &&

View File

@ -41,6 +41,7 @@ public:
void setBusy(const QString& dsId, bool busy);
void clearAllBusy(); // 撤回本段所有 spinner失败兜底
void selectItem(const QString& dsId); // 程序化选中某行(VTK→list 反向联动);空/未找到=清选中
void clearSelection(); // 清本段树选中(信号阻断,不回发 datasetSelected);供跨段全列互斥用
QStringList checkedIds() const { return checkedDsIds(); } // 当前勾选 ds异常显隐同步用
void refreshArrayFilter() { refreshArrayCombo(); } // 装置枚举异步加载后重填下拉
bool isExpanded() const; // 段头展开态(供外层按折叠状态重分配 stretch实现"折叠向上收"