From 297775ebd02aed982d24f08b0d8f711af6d752a6 Mon Sep 17 00:00:00 2001 From: lh <2334563547@qq.com> Date: Thu, 10 Sep 2026 10:42:38 +0800 Subject: [PATCH] =?UTF-8?q?fix(nmNum):=20=E4=BF=AE=E5=A4=8D=20PEBI=20?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E4=BF=AE=E6=94=B9=E5=90=8E=E7=9A=84=E5=9C=B0?= =?UTF-8?q?=E5=9B=BE=E4=B8=8E=E7=BD=91=E6=A0=BC=E5=88=B7=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 增加属性实际编辑通知,避免相同值重复推进计算输入版本 - 区分网格输入与仅求解输入,按参数类型失效网格或结果 - 监听井数据变化并刷新 Map,补齐井对象替换后的信号重绑定 - GridControl 变化后通知网格窗口,并同步最新控制值 - 修复井图元刷新接口访问权限导致的编译错误 --- Include/nmNum/nmData/nmAttrRegistry.h | 4 ++ Include/nmNum/nmData/nmDataAnalyzeManager.h | 5 ++ Include/nmNum/nmPlot/nmPlotGraphicBinder.h | 3 +- Src/nmNum/nmData/nmAttrRegistry.cpp | 12 ++++ Src/nmNum/nmData/nmDataAnalyzeManager.cpp | 62 ++++++++++++++++++++- Src/nmNum/nmPlot/nmPlotGraphicBinder.cpp | 34 +++++++++++ Src/nmNum/nmSubWnd/nmSubWndGrid.cpp | 6 ++ 7 files changed, 123 insertions(+), 3 deletions(-) diff --git a/Include/nmNum/nmData/nmAttrRegistry.h b/Include/nmNum/nmData/nmAttrRegistry.h index f494cee..ed2a05b 100644 --- a/Include/nmNum/nmData/nmAttrRegistry.h +++ b/Include/nmNum/nmData/nmAttrRegistry.h @@ -55,6 +55,10 @@ signals: /// @brief Data→UI 方向:属性变更通知,携带 name 和新值 void sigAttrChanged(QString name, QVariant value); + /// @brief UI 已实际修改底层属性,供数据管理器推进网格或结果输入版本 + /// @note 与 sigAttrChanged 分开,避免外部数据刷新 UI 时被误判为用户编辑 + void sigAttrEdited(QString name, QVariant value); + private slots: /// @brief 监听 nmDataAttribute::sigValueChanged,用 sender() 反查 name diff --git a/Include/nmNum/nmData/nmDataAnalyzeManager.h b/Include/nmNum/nmData/nmDataAnalyzeManager.h index dd0c589..dca4be3 100644 --- a/Include/nmNum/nmData/nmDataAnalyzeManager.h +++ b/Include/nmNum/nmData/nmDataAnalyzeManager.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -832,6 +833,10 @@ public: /** @brief 并行结果快照或其结果井选择已经改变。 */ void sigPebiResultSnapshotChanged(); + private slots: + /** @brief 根据参数面板实际编辑的属性类型,使对应 PEBI 输入版本失效。 */ + void onRegisteredAttributeEdited(QString sName, QVariant oValue); + private: /** @brief 按 UUID 给当前实时井统一绑定或解除最后结果快照弱引用。 */ void rebindPebiResultSnapshotToWells(); diff --git a/Include/nmNum/nmPlot/nmPlotGraphicBinder.h b/Include/nmNum/nmPlot/nmPlotGraphicBinder.h index fa420a0..1037b76 100644 --- a/Include/nmNum/nmPlot/nmPlotGraphicBinder.h +++ b/Include/nmNum/nmPlot/nmPlotGraphicBinder.h @@ -187,7 +187,7 @@ public: // 同步井图元可见性到井数据 // 更新井图元的数据映射(编辑井后更换数据对象时使用) - void updateWellDataMapping(nmObjPointWell* pGraphic, nmDataWellBase* pNewData) { m_mapWellData[pGraphic] = pNewData; } + void updateWellDataMapping(nmObjPointWell* pGraphic, nmDataWellBase* pNewData); // 井相关数据中心委托方法 bool hasLayers() const; @@ -242,6 +242,7 @@ private slots: // 井图元信号 → 数据同步 void onGraphicWellVisibleChanged(bool bVisible); + void onWellDataChanged(); private: nmDataAnalyzeManager* m_pDataMgr; // 数据中心,不持有,外部注入 diff --git a/Src/nmNum/nmData/nmAttrRegistry.cpp b/Src/nmNum/nmData/nmAttrRegistry.cpp index 2742cfe..6309347 100644 --- a/Src/nmNum/nmData/nmAttrRegistry.cpp +++ b/Src/nmNum/nmData/nmAttrRegistry.cpp @@ -126,10 +126,22 @@ void nmAttrRegistry::setValue(QString name, QVariant value) return; } + // 控件重建或失去焦点时可能重复提交相同值;此类提交不能推进计算输入版本。 + const QVariant oOldValue = pAttr->getValue(); + if (oOldValue == value) { + return; + } + m_bSyncing = true; pAttr->setValue(value); // → nmDataAttribute 发 sigValueChanged // → onAttrValueChanged 检测 m_bSyncing=true → 跳过 sigAttrChanged m_bSyncing = false; + + // 属性已完成写入后再通知数据管理器,保证监听者读取到的是最终值。 + const QVariant oNewValue = pAttr->getValue(); + if (oOldValue != oNewValue) { + emit sigAttrEdited(name, oNewValue); + } } void nmAttrRegistry::onAttrValueChanged() diff --git a/Src/nmNum/nmData/nmDataAnalyzeManager.cpp b/Src/nmNum/nmData/nmDataAnalyzeManager.cpp index cef769f..6d30f50 100644 --- a/Src/nmNum/nmData/nmDataAnalyzeManager.cpp +++ b/Src/nmNum/nmData/nmDataAnalyzeManager.cpp @@ -607,6 +607,39 @@ static bool isGeometryParaAttrName(const QString& name) return false; } +// 参数注册名可能带对象编码前缀,判断时只匹配完整的基础参数后缀。 +static bool hasRegisteredAttributeBaseName( + const QString& sName, + const char* pBaseName) +{ + const QString sBaseName = QString::fromLatin1(pBaseName); + return sName == sBaseName || sName.endsWith(QString("_") + sBaseName); +} + +// 这里只区分网格输入和仅求解输入,不在界面层重新解释 PEBI 业务规则。 +static bool isPebiGridInputAttributeName(const QString& sName) +{ + static const char* GRID_INPUT_NAMES[] = { + "W_X", "W_Y", "W_Rw", + "W_FractureHalfLength", "W_FractureAngle", "W_Dfc", + "W_WellLength", "W_DrainAngle", "W_NumberOfFractures", + "F_X0", "F_Y0", "F_X1", "F_Y1", + "FT_X0", "FT_Y0", "FT_X1", "FT_Y1", + "BR_XMin", "BR_YMin", "BR_XMax", "BR_YMax", + "BC_CenterX", "BC_CenterY", "BC_Radius", + "BP_X", "BP_Y" + }; + const int nNameCount = sizeof(GRID_INPUT_NAMES) / + sizeof(GRID_INPUT_NAMES[0]); + for(int nIndex = 0; nIndex < nNameCount; ++nIndex) { + if(hasRegisteredAttributeBaseName(sName, + GRID_INPUT_NAMES[nIndex])) { + return true; + } + } + return false; +} + namespace { // 清空指定目录下的所有旧文件和子目录,但保留目录本身 bool clearDirectoryContents(const QString& dirPath) @@ -1329,6 +1362,8 @@ ZX_DEFINE_DYNAMIC(DataAnalyzeManager, nmDataAnalyzeManager) // 属性注册表 m_pAttrRegistry = new nmAttrRegistry(); + connect(m_pAttrRegistry, SIGNAL(sigAttrEdited(QString,QVariant)), + this, SLOT(onRegisteredAttributeEdited(QString,QVariant))); m_backgroundImageInfo.bIsVisible = false; // 初始化混合参数数据(Temp) @@ -4308,7 +4343,14 @@ bool nmDataAnalyzeManager::getIncludeOtherWells() const void nmDataAnalyzeManager::setPebiGridControl(double dGridControl) { + const quint64 nOldGridInputRevision = + m_oNumericalAnalysisCase.getGridInputRevision(); m_oNumericalAnalysisCase.setPebiGridControl(dGridControl); + if(nOldGridInputRevision != + m_oNumericalAnalysisCase.getGridInputRevision()) { + // 分析方案已完成网格和结果失效,这里只通知已打开的网格窗口刷新。 + emit dataChanged(); + } } double nmDataAnalyzeManager::getPebiGridControl() const @@ -4811,13 +4853,29 @@ nmDataWellBase* nmDataAnalyzeManager::getCurWellData() void nmDataAnalyzeManager::notifyDataChanged() { - // 现有属性编辑链路尚未细分“几何变化”和“仅求解输入变化”, - // 为保证正确性先采用保守策略:任一计算数据变化都使网格失效。 + // 本入口用于几何、井集合等网格输入;仅影响求解的参数应调用 + // invalidatePebiResults(),避免无意义地重建当前有效网格。 m_oNumericalAnalysisCase.invalidateGrid(); emit dataChanged(); } +void nmDataAnalyzeManager::onRegisteredAttributeEdited( + QString sName, + QVariant oValue) +{ + Q_UNUSED(oValue); + + if(isPebiGridInputAttributeName(sName)) { + // 几何及离散参数变化后,Map 使用数据对象重绘,网格窗口按新版本自动重建。 + notifyDataChanged(); + return; + } + + // 其余实时注册参数均属于求解输入,只使结果过期,保留当前有效网格。 + invalidatePebiResults(); +} + void nmDataAnalyzeManager::notifyGeometryListChanged() { m_oNumericalAnalysisCase.invalidateGrid(); diff --git a/Src/nmNum/nmPlot/nmPlotGraphicBinder.cpp b/Src/nmNum/nmPlot/nmPlotGraphicBinder.cpp index 7b479b5..9d5480a 100644 --- a/Src/nmNum/nmPlot/nmPlotGraphicBinder.cpp +++ b/Src/nmNum/nmPlot/nmPlotGraphicBinder.cpp @@ -1605,6 +1605,20 @@ void nmPlotGraphicBinder::bindWellToGraphic(nmObjPointWell* pGraphic, nmDataWell _connectWell(pGraphic, pData); } +void nmPlotGraphicBinder::updateWellDataMapping( + nmObjPointWell* pGraphic, + nmDataWellBase* pNewData) +{ + if (!pGraphic || !pNewData) return; + + // replaceWellData 已销毁旧井对象,其 QObject 连接会自动解除;这里补绑新对象。 + m_mapWellData[pGraphic] = pNewData; + connect(pNewData, SIGNAL(sigWellDataChanged()), + this, SLOT(onWellDataChanged()), Qt::UniqueConnection); + // nmObjPointWell 将 update() 收窄为 protected,通过公开基类接口触发虚刷新。 + static_cast(pGraphic)->update(); +} + // 删除井图元前,先由数据层确认删除成功,再断开信号并清理映射。 bool nmPlotGraphicBinder::removeWellBinding(nmObjPointWell* pGraphic) { @@ -1929,6 +1943,19 @@ void nmPlotGraphicBinder::onGraphicWellVisibleChanged(bool bVisible) pData->setPlotVisible(bVisible); } +void nmPlotGraphicBinder::onWellDataChanged() +{ + nmDataWellBase* pData = qobject_cast(sender()); + if (!pData) return; + + // 井图元在 paintBack 中读取实时坐标和裂缝几何,只需触发一次重绘。 + nmObjPointWell* pGraphic = m_mapWellData.key(pData, nullptr); + if (pGraphic) { + // 保持与 nmGuiPlot 的现有调用方式一致,避免访问井类的 protected override。 + static_cast(pGraphic)->update(); + } +} + bool nmPlotGraphicBinder::hasLayers() const { if (!m_pDataMgr) return false; @@ -1973,6 +2000,8 @@ void nmPlotGraphicBinder::_connectWell(nmObjPointWell* pGraphic, nmDataWellBase* connect(pGraphic, SIGNAL(sigObjVisibleChanged(bool)), this, SLOT(onGraphicWellVisibleChanged(bool))); + connect(pData, SIGNAL(sigWellDataChanged()), + this, SLOT(onWellDataChanged()), Qt::UniqueConnection); m_setBoundWellGraphics.insert(pGraphic); } @@ -1985,6 +2014,11 @@ void nmPlotGraphicBinder::_disconnectWell(nmObjPointWell* pGraphic) disconnect(pGraphic, SIGNAL(sigObjVisibleChanged(bool)), this, SLOT(onGraphicWellVisibleChanged(bool))); + nmDataWellBase* pData = m_mapWellData.value(pGraphic, nullptr); + if (pData) { + disconnect(pData, SIGNAL(sigWellDataChanged()), + this, SLOT(onWellDataChanged())); + } m_setBoundWellGraphics.remove(pGraphic); } diff --git a/Src/nmNum/nmSubWnd/nmSubWndGrid.cpp b/Src/nmNum/nmSubWnd/nmSubWndGrid.cpp index 4afc44b..c347df5 100644 --- a/Src/nmNum/nmSubWnd/nmSubWndGrid.cpp +++ b/Src/nmNum/nmSubWnd/nmSubWndGrid.cpp @@ -282,6 +282,12 @@ void nmSubWndGrid::onDataManagerChanged() if(sender() != m_pDataManager.data()) { return; } + + // GridControl 由分析方案统一持有,刷新前同步,避免窗口把旧局部值写回。 + nmDataAnalyzeManager* pDataManager = m_pDataManager.data(); + if(pDataManager != nullptr) { + m_dPebiGridControl = pDataManager->getPebiGridControl(); + } updateGrid(); }