fix(vtk): 修审查问题(H1 setDatasets信号风暴/H2异步陈旧批次竞态/I1全屏按钮互斥)

This commit is contained in:
gaozheng 2026-06-16 17:08:45 +08:00
parent 24d88530af
commit 5e15941cd2
5 changed files with 59 additions and 19 deletions

View File

@ -62,6 +62,7 @@
#include <QStatusBar>
#include <QStyle>
#include <QSurfaceFormat>
#include <QSignalBlocker>
#include <QTimer>
#include <QToolBar>
#include <QTreeWidget>
@ -593,9 +594,11 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
// ── 左上对象树勾选 → 拉取各 TM 的 ds 子树按维度分发到三栏列表spec §6.1/§8──
// 渲染由三栏勾选框驱动Task 7Column3DDataset::checkedDatasetsChanged → setCheckedDatasets
auto generation = std::make_shared<unsigned long long>(0);
QObject::connect(
objectTree, &geopro::app::ObjectTreePanel::checkedTmsChanged, &window,
[&projectRepo, &nav, drawer, emptyState](const QStringList& tmIds) {
[&projectRepo, &nav, drawer, emptyState, generation](const QStringList& tmIds) {
const unsigned long long myGen = ++(*generation);
emptyState->setVisible(tmIds.isEmpty()); // 有勾选→隐藏引导层,露出中央渲染
if (tmIds.isEmpty()) {
drawer->col3D()->setDatasets({});
@ -606,7 +609,8 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
// 多 TM 异步汇总:每个 TM 取整棵 ds 子树,全部回来后按维度分发到三栏。
auto acc = std::make_shared<std::vector<geopro::data::DsRow>>();
auto remaining = std::make_shared<int>(tmIds.size());
auto finish = [acc, drawer]() {
auto finish = [acc, drawer, generation, myGen]() {
if (*generation != myGen) return; // 已被更新的勾选批次取代→丢弃陈旧结果
geopro::app::DimBuckets b = geopro::app::splitByDimension(*acc);
drawer->col3D()->setDatasets(b.dim3D);
drawer->col2D()->setDatasets(b.dim2D);
@ -771,14 +775,22 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
if (vtkFsBtn) {
vtkFsBtn->setCheckable(true);
QObject::connect(vtkFsBtn, &QToolButton::toggled, &window,
[applyFullscreen, vtkDock, allDocks](bool on) {
[applyFullscreen, vtkDock, allDocks, detailFsBtn](bool on) {
if (on && detailFsBtn && detailFsBtn->isChecked()) {
QSignalBlocker b(detailFsBtn);
detailFsBtn->setChecked(false);
}
applyFullscreen(vtkDock, allDocks, on);
});
}
if (detailFsBtn) {
detailFsBtn->setCheckable(true);
QObject::connect(detailFsBtn, &QToolButton::toggled, &window,
[applyFullscreen, detailDock, allDocks](bool on) {
[applyFullscreen, detailDock, allDocks, vtkFsBtn](bool on) {
if (on && vtkFsBtn && vtkFsBtn->isChecked()) {
QSignalBlocker b(vtkFsBtn);
vtkFsBtn->setChecked(false);
}
applyFullscreen(detailDock, allDocks, on);
});
}

View File

@ -5,6 +5,7 @@
#include <QFormLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QSignalBlocker>
#include <QTreeWidget>
#include <QTreeWidgetItemIterator>
#include <QVBoxLayout>
@ -78,12 +79,20 @@ Column2DDataset::Column2DDataset(QWidget* parent) : QWidget(parent) {
}
void Column2DDataset::setDatasets(const std::vector<geopro::data::DsRow>& rows) {
{
QSignalBlocker blocker(list_);
populateDatasetList(list_, rows, /*append=*/false);
for (QTreeWidgetItemIterator it(list_); *it; ++it) {
(*it)->setFlags((*it)->flags() | Qt::ItemIsUserCheckable);
if ((*it)->checkState(0) != Qt::Checked)
(*it)->setCheckState(0, Qt::Unchecked);
}
} // blocker released here
// 填充后统一发一次(新载入必为空选):清掉上一次的渲染勾选
QStringList ids;
for (QTreeWidgetItemIterator it(list_); *it; ++it)
if ((*it)->checkState(0) == Qt::Checked)
ids << (*it)->data(0, kDsIdRole).toString();
emit checkedDatasetsChanged(ids);
}
} // namespace geopro::app

View File

@ -1,6 +1,7 @@
#include "panels/columns/Column3DAnalysis.hpp"
#include <QMenu>
#include <QSignalBlocker>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QTreeWidgetItemIterator>
@ -37,12 +38,20 @@ Column3DAnalysis::Column3DAnalysis(QWidget* parent) : QWidget(parent) {
}
void Column3DAnalysis::setDatasets(const std::vector<geopro::data::DsRow>& rows) {
{
QSignalBlocker blocker(tree_);
populateDatasetList(tree_, rows, /*append=*/false);
for (QTreeWidgetItemIterator it(tree_); *it; ++it) {
(*it)->setFlags((*it)->flags() | Qt::ItemIsUserCheckable);
if ((*it)->checkState(0) != Qt::Checked)
(*it)->setCheckState(0, Qt::Unchecked);
}
} // blocker released here
// 填充后统一发一次(新载入必为空选):清掉上一次的渲染勾选
QStringList ids;
for (QTreeWidgetItemIterator it(tree_); *it; ++it)
if ((*it)->checkState(0) == Qt::Checked)
ids << (*it)->data(0, kDsIdRole).toString();
emit checkedItemsChanged(ids);
}
void Column3DAnalysis::onContextMenu(const QPoint& pos) {

View File

@ -15,6 +15,7 @@ class Column3DAnalysis : public QWidget {
Q_OBJECT
public:
explicit Column3DAnalysis(QWidget* parent = nullptr);
// 本期:按 ds parentId 建树(切片挂源数据下);完整 对象→三维体→切片 三级树待后端数据(P4)。
void setDatasets(const std::vector<geopro::data::DsRow>& rows); // Analysis 维度(三维体/切片)
signals:

View File

@ -5,6 +5,7 @@
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QSignalBlocker>
#include <QSlider>
#include <QTreeWidget>
#include <QTreeWidgetItemIterator>
@ -125,12 +126,20 @@ Column3DDataset::Column3DDataset(QWidget* parent) : QWidget(parent) {
}
void Column3DDataset::setDatasets(const std::vector<geopro::data::DsRow>& rows) {
{
QSignalBlocker blocker(list_);
populateDatasetList(list_, rows, /*append=*/false);
for (QTreeWidgetItemIterator it(list_); *it; ++it) {
(*it)->setFlags((*it)->flags() | Qt::ItemIsUserCheckable);
if ((*it)->checkState(0) != Qt::Checked)
(*it)->setCheckState(0, Qt::Unchecked);
}
} // blocker released here
// 填充后统一发一次(新载入必为空选):清掉上一次的渲染勾选
QStringList ids;
for (QTreeWidgetItemIterator it(list_); *it; ++it)
if ((*it)->checkState(0) == Qt::Checked)
ids << (*it)->data(0, kDsIdRole).toString();
emit checkedDatasetsChanged(ids);
}
} // namespace geopro::app