支持PEBI多井参数分组显示及双向同步

- 按wellCode动态生成井参数分组及唯一参数名
- 接入属性注册表,实现UI与井数据双向同步
- 支持井增删、清空及类型切换后的面板重建
- 清理失效井属性注册,兼容特殊井编码
feature/nm-para-property-20260615
lh 2 months ago
parent b86696ec2c
commit dcb4db2dfb

Binary file not shown.

@ -1,4 +1,4 @@
#pragma once
#pragma once
#include <QObject>
#include <QMap>
@ -35,9 +35,15 @@ public:
/// @return name→value 映射,未找到的跳过
QMap<QString, QVariant> collect(const QStringList& names) const;
/// @brief 注销单个属性,断开信号连接
void unregAttr(QString name);
/// @brief 批量通知所有已注册属性刷新 UI外部批量修改数据后调用
void refreshAll();
/// @brief 返回所有已注册的属性名列表
QStringList registeredNames() const;
public slots:
/// @brief UI→Data 方向:按 name dispatch 到 nmDataAttribute::setValue

@ -547,12 +547,17 @@ class NM_DATA_EXPORT nmDataAnalyzeManager : public ZxDataObjectBin
// 获取属性注册表
nmAttrRegistry* getAttrRegistry() const;
/// @brief 注册所有井的参数到 nmAttrRegistry
/// @brief 同步所有井的参数到 nmAttrRegistry
/// @note wellCode + "_W_XX" 作为注册名,使双向绑定链路适用于井参数
void registerWellAttrs();
/// @note 增量同步:自动清理已删除井的注册,注册新增井的参数
void syncWellAttrs();
signals:
void dataChanged();
/// @brief 井数据准备完成信号
void sigWellAdded(QString wellCode, QString wellName, QStringList baseParas);
/// @brief 井删除信号removeWell 发出)
void sigWellRemoved(QString wellCode, QString wellName);
private:
// 存储井的数据

@ -1,4 +1,4 @@
#pragma once
#pragma once
#include "nmGUI_global.h"
#include "iGridRowUtils.h"
@ -98,6 +98,10 @@ public:
/// @return 剥离后的基名;若无前缀匹配则返回空字符串
QString stripWellPrefix(QString sPara) const;
/// @brief 获取参数项所属井分组的唯一前缀
/// @note 参考多对象 UI 的 Layer 标记方式,沿父链查找井分组。
virtual QString getUpperLayerTagOf(iGridRowItem* pItem) override;
// ================================================================
// 序列化
// ================================================================
@ -168,11 +172,6 @@ protected:
/// @param bDnMode 是否为设计模式
void buildWellGroups(QMap<QString, QStringList>& mapWellParas, bool bDnMode);
/// @brief 为井分组中的参数项补齐 nameInner含 wellCode 前缀)
/// @param mapWellParas wellCode → 基参数名列表
/// @note 必须在 bkAllItems 之后调用,因为 bkAllItems 会重建 m_vecAllItems
void applyWellParaNameInners(const QMap<QString, QStringList>& mapWellParas);
public slots:
/// @brief 获取指定参数的当前值(供子项内部查询用)
@ -186,16 +185,4 @@ private:
/// @brief 井名映射wellCode → 显示名)
QMap<QString, QString> m_mapWellNames;
private slots:
/// @brief 参数值改变后的回调iGridRowItem::sigValueChanged 触发)
/// @note 立即 emit sigParaChanged确保数据层与 UI 始终同步
void slotItemValueChanged(QString sPara, QVariant o);
signals:
/// @brief 参数值变更信号(简化版,供 nmAttrRegistry 同步用)
/// @param name 参数名(来自当前激活项的 Name
/// @param value 变更后的值
void sigParaChanged(QString name, QVariant value);
};

@ -15,6 +15,8 @@ class QMdiSubWindow;
class ZxMdiSubWindow;
class QEvent;
class iSubWndFitting;
class nmDataAnalyzeManager;
class nmWxParaPropertyPebi;
// 本来主要是为数值部分提供SubWnd初始化构造的方法
class NM_SUB_WND_EXPORT nmSubWndUtils : public QObject
@ -116,6 +118,12 @@ public:
/// @brief 获取缓存的TabWidget指针确保弹窗与MDI切换使用同一个容器指针比较才能正确
ZxTabWidget* getTabWidget() const { return m_pTabWx; }
/// @brief 建立井列表变化与PEBI参数面板的刷新连接
/// @param pDataManager 数据管理器
/// @param pParaWx PEBI参数面板
static void connectWellListSignals(nmDataAnalyzeManager* pDataManager,
nmWxParaPropertyPebi* pParaWx);
public slots:
// 声明处理 ZxTabWidget 切换的槽函数
// 信号 currentChanged(int) 传递一个 int 参数

@ -1,9 +1,10 @@
#pragma once
#pragma once
#include "iDlgBase.h"
#include "nmSubWxs_global.h"
class nmGridRowUtils;
class nmDataAnalyzeManager;
/// @brief PEBI求解器专用的参数输入/编辑属性对话框窗体
/// @note 与 nmWxParaProperty 结构一致,区别在于内部使用 nmGridRowUtilsNM子类
@ -29,6 +30,13 @@ public:
virtual void refreshUIs(QStringList& listParas, bool bReserveOlds = true,
QMap<QString, QString> mapWellNames = QMap<QString, QString>());
/// @brief 从数据管理器重建完整参数面板
/// @note XML 中井参数只定义一份,运行时按 wellCode 创建多个对象分组。
void rebuildAllParas();
/// @brief 设置数据管理器引用(用于面板重建时获取井列表)
void setDataManager(nmDataAnalyzeManager* mgr) { m_pDataManager = mgr; }
// 允许备份/恢复原有的参数内容
virtual void backupOldParas(QMap<QString, QVariant>& map,
QStringList& listParas);
@ -56,10 +64,18 @@ public slots:
// help msg
virtual void slotHelpMsg(QString& s);
/// @brief 响应参数控件值改变,并转发给数据注册表
virtual void slotParaCtrlValueChanged(QString sPara, QVariant o);
/// @brief 设置参数值的槽(供 nmAttrRegistry::sigAttrChanged 连接用)
/// @note setParaValue 是 virtual 函数在 public 区,不能直接作为 SLOT
void slotSetParaValue(QString sPara, QVariant o);
/// @brief 井新增时按当前井列表刷新面板
void slotWellAdded(QString wellCode, QString wellName, QStringList paras);
/// @brief 井删除时按当前井列表刷新面板
void slotWellRemoved(QString wellCode, QString wellName);
protected:
virtual void paintEvent(QPaintEvent*);
@ -76,9 +92,12 @@ protected:
// Help
QTextEdit* m_pHelpBox;
// 数据管理器引用(用于全量重建面板时获取井列表)
nmDataAnalyzeManager* m_pDataManager;
signals:
/// @brief 参数值变更信号(转发 nmGridRowUtils::sigParaChanged
/// @brief 参数值变更信号(由 slotParaCtrlValueChanged 转发
/// @param name 参数名
/// @param value 变更后的值
void sigParaChanged(QString name, QVariant value);

@ -1,4 +1,4 @@
#include "nmAttrRegistry.h"
#include "nmAttrRegistry.h"
#include "nmDataAttribute.h"
nmAttrRegistry::nmAttrRegistry(QObject* parent)
@ -21,10 +21,15 @@ void nmAttrRegistry::regAttr(QString name, nmDataAttribute* pAttr)
return;
}
if (m_nameToPtr.value(name, nullptr) == pAttr &&
m_ptrToName.value(pAttr) == name) {
return;
}
// 如果同名已注册,先断开旧连接
if (m_nameToPtr.contains(name)) {
nmDataAttribute* pOld = m_nameToPtr[name];
if (pOld != nullptr && pOld != pAttr) {
if (pOld != nullptr) {
disconnect(pOld, SIGNAL(sigValueChanged()), this, SLOT(onAttrValueChanged()));
disconnect(pOld, SIGNAL(destroyed(QObject*)), this, SLOT(onAttrDestroyed(QObject*)));
m_ptrToName.remove(pOld);
@ -36,6 +41,8 @@ void nmAttrRegistry::regAttr(QString name, nmDataAttribute* pAttr)
QString oldName = m_ptrToName[pAttr];
if (oldName != name) {
m_nameToPtr.remove(oldName);
disconnect(pAttr, SIGNAL(sigValueChanged()), this, SLOT(onAttrValueChanged()));
disconnect(pAttr, SIGNAL(destroyed(QObject*)), this, SLOT(onAttrDestroyed(QObject*)));
}
}
@ -44,9 +51,9 @@ void nmAttrRegistry::regAttr(QString name, nmDataAttribute* pAttr)
// 连接 nmDataAttribute 的信号
connect(pAttr, SIGNAL(sigValueChanged()),
this, SLOT(onAttrValueChanged()));
this, SLOT(onAttrValueChanged()), Qt::UniqueConnection);
connect(pAttr, SIGNAL(destroyed(QObject*)),
this, SLOT(onAttrDestroyed(QObject*)));
this, SLOT(onAttrDestroyed(QObject*)), Qt::UniqueConnection);
}
void nmAttrRegistry::clear()
@ -65,6 +72,24 @@ void nmAttrRegistry::clear()
m_ptrToName.clear();
}
void nmAttrRegistry::unregAttr(QString name)
{
if (name.isEmpty()) {
return;
}
nmDataAttribute* pAttr = m_nameToPtr.value(name, nullptr);
if (pAttr == nullptr) {
return;
}
disconnect(pAttr, SIGNAL(sigValueChanged()), this, SLOT(onAttrValueChanged()));
disconnect(pAttr, SIGNAL(destroyed(QObject*)), this, SLOT(onAttrDestroyed(QObject*)));
m_ptrToName.remove(pAttr);
m_nameToPtr.remove(name);
}
QMap<QString, QVariant> nmAttrRegistry::collect(const QStringList& names) const
{
QMap<QString, QVariant> mapResult;
@ -89,6 +114,11 @@ void nmAttrRegistry::refreshAll()
}
}
QStringList nmAttrRegistry::registeredNames() const
{
return m_nameToPtr.keys();
}
void nmAttrRegistry::setValue(QString name, QVariant value)
{
nmDataAttribute* pAttr = m_nameToPtr.value(name, nullptr);

@ -1,4 +1,4 @@
#include "nmDataAnalyzeManager.h"
#include "nmDataAnalyzeManager.h"
#include "nmAttrRegistry.h"
@ -13,6 +13,7 @@
#include "ZxDataWell.h"
#include "ZxBaseUtil.h"
#include <QSet>
#include "zxLogInstance.h"
#include "nmDataReservoir.h"
@ -71,6 +72,40 @@
#include <QFileInfo>
#include <QMessageBox>
// 井基参数名 → 数据成员访问器的映射描述
struct WellParaDesc {
const char* sName; // 参数基名,如 "W_X"
nmDataAttribute* (*getAttr)(nmDataWellBase&); // 访问器函数指针
};
static nmDataAttribute* getParaX(nmDataWellBase& w) { return &w.getX(); }
static nmDataAttribute* getParaY(nmDataWellBase& w) { return &w.getY(); }
static nmDataAttribute* getParaRw(nmDataWellBase& w) { return &w.getRadius(); }
static nmDataAttribute* getParaC(nmDataWellBase& w) { return &w.getWellboreStorage(); }
static nmDataAttribute* getParaSkin(nmDataWellBase& w)
{
return w.getPerforationCount() > 0 ? &w.getPerforation(0)->getSkin() : NULL;
}
static const WellParaDesc WELL_PARA_DESCS[] = {
{"W_X", &getParaX},
{"W_Y", &getParaY},
{"W_Rw", &getParaRw},
{"W_C", &getParaC},
{"W_Skin", &getParaSkin},
};
static const int WELL_PARA_DESC_COUNT = sizeof(WELL_PARA_DESCS) / sizeof(WELL_PARA_DESCS[0]);
static bool isWellParaAttrName(const QString& name)
{
for (int i = 0; i < WELL_PARA_DESC_COUNT; ++i) {
if (name.endsWith(QString("_") + WELL_PARA_DESCS[i].sName)) {
return true;
}
}
return false;
}
namespace {
// 清空指定目录下的所有旧文件和子目录,但保留目录本身
bool clearDirectoryContents(const QString& dirPath)
@ -579,6 +614,9 @@ nmDataWellBase* nmDataAnalyzeManager::changeWellType(nmDataWellBase* pOldWellDat
return nullptr;
}
const QString wellCode = pOldWellData->getWellCode();
const QString wellName = pOldWellData->getWellName();
if(!removeWell(pOldWellData)) {
return nullptr;
}
@ -589,6 +627,10 @@ nmDataWellBase* nmDataAnalyzeManager::changeWellType(nmDataWellBase* pOldWellDat
return nullptr;
}
pNewWellData->setWellCode(wellCode);
pNewWellData->setWellName(wellName);
appendNmWellData(pNewWellData);
return pNewWellData;
}
@ -621,18 +663,33 @@ bool nmDataAnalyzeManager::removeWell(nmDataWellBase* pWellData)
}
}
// 遍历 m_vWellData找到并移除指定的井对象
for(auto it = m_vWellData.begin(); it != m_vWellData.end(); ++it) {
if(*it == pWellData) {
m_vWellData.erase(it);
delete pWellData;
pWellData = nullptr;
emit dataChanged();
return true; // 成功移除并删除井对象
if (!m_vWellData.contains(pWellData)) {
return false;
}
QString removedCode = pWellData->getWellCode();
QString removedName = pWellData->getWellName();
// 先从 registry 清理该井的所有属性,避免野指针
if (m_pAttrRegistry) {
for (int i = 0; i < WELL_PARA_DESC_COUNT; ++i) {
QString name = removedCode + "_" + WELL_PARA_DESCS[i].sName;
m_pAttrRegistry->unregAttr(name);
}
}
// 倒序移除全部匹配项,兼容旧逻辑可能遗留的重复指针。
for (int i = m_vWellData.size() - 1; i >= 0; --i) {
if (m_vWellData[i] == pWellData) {
m_vWellData.remove(i);
}
}
delete pWellData;
pWellData = nullptr;
return false; // 如果未找到该井对象,返回 false
emit sigWellRemoved(removedCode, removedName);
emit dataChanged();
return true;
}
void nmDataAnalyzeManager::removeWellDataAndPlot(nmDataWellBase* pWellData)
@ -659,16 +716,37 @@ void nmDataAnalyzeManager::removeWellDataAndPlot(nmDataWellBase* pWellData)
void nmDataAnalyzeManager::clearAllWellData()
{
// 遍历并删除所有井对象
typedef QPair<QString, QString> WellIdentity;
QList<WellIdentity> removedWells;
// 遍历并删除所有井对象,兼容旧逻辑可能遗留的重复指针。
QSet<nmDataWellBase*> deletedWells;
foreach(nmDataWellBase* pWell, m_vWellData) {
if(pWell != nullptr) {
if(pWell != nullptr && !deletedWells.contains(pWell)) {
deletedWells.insert(pWell);
removedWells.append(qMakePair(pWell->getWellCode(), pWell->getWellName()));
delete pWell;
pWell = nullptr;
}
}
// 清空数组
m_vWellData.clear();
m_pCurDataWell = nullptr;
m_vecCalculationWells.clear();
// 清理 registry 中所有井相关属性
if (m_pAttrRegistry) {
foreach (const QString& name, m_pAttrRegistry->registeredNames()) {
if (isWellParaAttrName(name)) {
m_pAttrRegistry->unregAttr(name);
}
}
}
foreach (const WellIdentity& well, removedWells) {
emit sigWellRemoved(well.first, well.second);
}
emit dataChanged();
}
QVector<nmDataWellBase*> nmDataAnalyzeManager::getWellDataList() const
@ -1264,13 +1342,44 @@ void nmDataAnalyzeManager::appendWellData(ZxDataWell* pWellData)
// 设置流量段索引
pHFracturedWell->setIndexF(nIndexF);
}
// 通知面板新增井分组
{
syncWellAttrs();
QString code = pWellData->getCode();
QString name = pWellData->getName();
QStringList paras;
for (int i = 0; i < WELL_PARA_DESC_COUNT; ++i) {
paras << WELL_PARA_DESCS[i].sName;
}
emit sigWellAdded(code, name, paras);
if (m_pAttrRegistry)
m_pAttrRegistry->refreshAll();
}
}
void nmDataAnalyzeManager::appendNmWellData(nmDataWellBase* pWellData)
{
if (pWellData == nullptr)
return;
m_vWellData.append(pWellData);
if (!m_vWellData.contains(pWellData))
{
m_vWellData.append(pWellData);
}
// 通知面板新增井分组
{
syncWellAttrs();
QString code = pWellData->getWellCode();
QString name = pWellData->getWellName();
QStringList paras;
for (int i = 0; i < WELL_PARA_DESC_COUNT; ++i) {
paras << WELL_PARA_DESCS[i].sName;
}
emit sigWellAdded(code, name, paras);
if (m_pAttrRegistry)
m_pAttrRegistry->refreshAll();
}
}
/// @brief 创建油藏数据对象从界面读取PVT单值和分层数据构建reservoir对象
@ -1356,48 +1465,40 @@ nmAttrRegistry* nmDataAnalyzeManager::getAttrRegistry() const
return m_pAttrRegistry;
}
// 井基参数名 → 数据成员访问器的映射描述
struct WellParaDesc {
const char* sName; // 参数基名,如 "W_X"
nmDataAttribute* (*getAttr)(nmDataWellBase&); // 访问器函数指针
};
static nmDataAttribute* getParaX(nmDataWellBase& w) { return &w.getX(); }
static nmDataAttribute* getParaY(nmDataWellBase& w) { return &w.getY(); }
static nmDataAttribute* getParaRw(nmDataWellBase& w) { return &w.getRadius(); }
static nmDataAttribute* getParaC(nmDataWellBase& w) { return &w.getWellboreStorage(); }
static nmDataAttribute* getParaSkin(nmDataWellBase& w)
{
return w.getPerforationCount() > 0 ? &w.getPerforation(0)->getSkin() : NULL;
}
static const WellParaDesc WELL_PARA_DESCS[] = {
{"W_X", &getParaX},
{"W_Y", &getParaY},
{"W_Rw", &getParaRw},
{"W_C", &getParaC},
{"W_Skin", &getParaSkin},
};
static const int WELL_PARA_DESC_COUNT = sizeof(WELL_PARA_DESCS) / sizeof(WELL_PARA_DESCS[0]);
void nmDataAnalyzeManager::registerWellAttrs()
void nmDataAnalyzeManager::syncWellAttrs()
{
if (m_pAttrRegistry == NULL) return;
QSet<QString> activeAttrNames;
QSet<QString> activeWellCodes;
foreach (nmDataWellBase* pWell, m_vWellData)
{
if (pWell == nullptr) continue;
QString code = pWell->getWellCode();
if (code.isEmpty()) continue;
if (code.isEmpty() || activeWellCodes.contains(code)) continue;
activeWellCodes.insert(code);
for (int i = 0; i < WELL_PARA_DESC_COUNT; ++i)
{
nmDataAttribute* pAttr = WELL_PARA_DESCS[i].getAttr(*pWell);
if (pAttr != NULL)
{
m_pAttrRegistry->regAttr(code + "_" + WELL_PARA_DESCS[i].sName, pAttr);
QString name = code + "_" + WELL_PARA_DESCS[i].sName;
activeAttrNames.insert(name);
m_pAttrRegistry->regAttr(name, pAttr);
}
}
}
// 精确清理已经不存在的井参数注册,兼容 wellCode 自身包含下划线。
foreach (const QString& name, m_pAttrRegistry->registeredNames())
{
if (isWellParaAttrName(name) && !activeAttrNames.contains(name))
{
m_pAttrRegistry->unregAttr(name);
}
}
}
nmDataReservoir nmDataAnalyzeManager::getReservoirDataCopy() const
@ -1679,8 +1780,8 @@ void nmDataAnalyzeManager::applyDiagnosticResults(nmDataDiagnostic* diagnostic,
nmDataPerforation* firstPerforation = wellData->getPerforation(0);
if(firstPerforation) {
firstPerforation->getSkin().setValue(diagnosticSkin);
}
}
}
}
}
nmDataAutomaticFitting* nmDataAnalyzeManager::createAutomaticFittingData()

@ -1,14 +1,37 @@
#include "nmGridRowUtils.h"
#include "nmGridRowUtils.h"
#include "iGridRowGroup.h"
#include "iParameter.h"
#include "iSysParaHelper.h"
// 按字符串长度降序比较(用于最长前缀优先匹配)
// 井编码可能互为前缀,拆分参数时必须优先匹配更长的编码。
static bool longerStringFirst(const QString& a, const QString& b)
{
return a.length() > b.length();
}
namespace {
// 参考多对象 UI 中的 tGridRowGroupLayer对象分组只负责标题和折叠
// 不创建普通参数编辑器,但仍完成基类要求的其余初始化。
class nmWellGridRowGroup : public iGridRowGroup
{
public:
explicit nmWellGridRowGroup(iGridRowItem* pParent = nullptr)
: iGridRowGroup(pParent)
{
}
virtual void initEditor()
{
}
virtual void configEditor()
{
}
};
}
// ================================================================
// 构造与析构
// ================================================================
@ -60,9 +83,6 @@ bool nmGridRowUtils::buildRowUtils(QStringList listParas,
bkAllItems();
bindItems();
// 为井参数项补齐 nameInner含 wellCode 前缀)
applyWellParaNameInners(mapWellParas);
double h = getUtilHeight();
QRectF rt = QRectF(0, 0, 300, h);
setBounds(rt);
@ -72,28 +92,6 @@ bool nmGridRowUtils::buildRowUtils(QStringList listParas,
return true;
}
void nmGridRowUtils::applyWellParaNameInners(const QMap<QString, QStringList>& mapWellParas)
{
foreach (const QString& sCode, m_mapWellNames.keys())
{
QString sPrefix = sCode + "_";
foreach (iGridRowItem* pItem, m_vecAllItems)
{
if (!pItem)
continue;
const QStringList& listBases = mapWellParas.value(sCode);
foreach (const QString& sBase, listBases)
{
if (pItem->getName() == sBase && !sBase.isEmpty())
{
pItem->setNameInner(sPrefix + sBase);
break;
}
}
}
}
}
// ================================================================
// 参数读写
// ================================================================
@ -110,7 +108,10 @@ bool nmGridRowUtils::getParaValue(QString sPara, QVariant& o)
QString nmGridRowUtils::stripWellPrefix(QString sPara) const
{
foreach (const QString& sCode, m_mapWellNames.keys())
QList<QString> listCodes = m_mapWellNames.keys();
qSort(listCodes.begin(), listCodes.end(), longerStringFirst);
foreach (const QString& sCode, listCodes)
{
QString sPrefix = sCode + "_";
if (sPara.startsWith(sPrefix))
@ -121,6 +122,25 @@ QString nmGridRowUtils::stripWellPrefix(QString sPara) const
return QString();
}
QString nmGridRowUtils::getUpperLayerTagOf(iGridRowItem* pItem)
{
iGridRowItem* pCurrent = pItem;
while (pCurrent != nullptr)
{
const QString sTagLayer = pCurrent->getTagLayer();
foreach (const QString& sCode, m_mapWellNames.keys())
{
if (sTagLayer == sCode + "_")
{
return sTagLayer;
}
}
pCurrent = pCurrent->getParent();
}
return QString();
}
bool nmGridRowUtils::getAllParaValues(QMap<QString, QVariant>& map,
bool bOnlyFitted,
bool bClearMap)
@ -200,12 +220,11 @@ bool nmGridRowUtils::createAndAddItem(iGridRowItem* pParent,
iParameter* p,
QString sPara)
{
// 检查父级是否为井分组,若是则设置 nameInner含井前缀
QString sNameInner;
if (nullptr != pParent)
if (pParent != nullptr && p != nullptr)
{
QString sTagLayer = pParent->getTagLayer();
if (!sTagLayer.isEmpty() && nullptr != p)
const QString sTagLayer = getUpperLayerTagOf(pParent);
if (!sTagLayer.isEmpty())
{
sNameInner = sTagLayer + p->m_sName;
}
@ -236,10 +255,6 @@ bool nmGridRowUtils::createAndAddItem(iGridRowItem* pParent,
void nmGridRowUtils::connectSignalsOf(iGridRowItem* p)
{
iGridRowUtils::connectSignalsOf(p);
// 连接 sigValueChanged值改变立即同步到数据层
connect(p, SIGNAL(sigValueChanged(QString, QVariant)),
this, SLOT(slotItemValueChanged(QString, QVariant)));
}
void nmGridRowUtils::bindItems()
@ -258,7 +273,6 @@ void nmGridRowUtils::splitWellParas(QStringList listParas,
listRes.clear();
mapWellParas.clear();
// 按长度降序排列wellCode确保最长匹配优先
QList<QString> listCodes = m_mapWellNames.keys();
qSort(listCodes.begin(), listCodes.end(), longerStringFirst);
@ -305,13 +319,14 @@ void nmGridRowUtils::buildWellGroups(QMap<QString, QStringList>& mapWellParas,
// 显示名称
QString sWellName = sCode;
if (m_mapWellNames.contains(sCode))
if (m_mapWellNames.contains(sCode) &&
!m_mapWellNames.value(sCode).isEmpty())
{
sWellName = m_mapWellNames[sCode];
}
// 创建井分组(纯标题,不需要编辑器)
iGridRowGroup* pGroup = new iGridRowGroup(nullptr);
// 参考多对象 UI 的 Layer 分组:用父节点的 tagLayer 标记对象作用域。
nmWellGridRowGroup* pGroup = new nmWellGridRowGroup(nullptr);
Q_ASSERT(nullptr != pGroup);
pGroup->setParaSrcTag(m_sParaSrcTag);
pGroup->setTagInner(sWellName); // Group 标题
@ -319,6 +334,10 @@ void nmGridRowUtils::buildWellGroups(QMap<QString, QStringList>& mapWellParas,
connectSignalsOf(pGroup);
pGroup->setDlgBase(this);
pGroup->initEditor();
pGroup->configEditor();
pGroup->setSplitPos(m_dSplitPos);
pGroup->initOtherEditors();
m_vecGridItems.append(pGroup);
@ -327,15 +346,6 @@ void nmGridRowUtils::buildWellGroups(QMap<QString, QStringList>& mapWellParas,
}
}
// ================================================================
// 槽函数
// ================================================================
void nmGridRowUtils::slotItemValueChanged(QString sPara, QVariant o)
{
emit sigParaChanged(sPara, o);
}
void nmGridRowUtils::slotGetValueOf(QString sPara, QVariant& o, bool& bOk)
{
iGridRowUtils::slotGetValueOf(sPara, o, bOk);

@ -317,6 +317,7 @@ void nmGuiPlot::initDefultGeoObj()
}
m_VerticalWell->setWellName(pWellData->getName());
m_VerticalWell->setWellCode(pWellData->getCode());
nmDataAttribute tempAttr = m_VerticalWell->getX();
tempAttr.setValue(pWellData->getLocationX());
m_VerticalWell->setX(tempAttr);
@ -353,6 +354,7 @@ void nmGuiPlot::initDefultGeoObj()
}
m_VFracturedWell->setWellName(pWellData->getName());
m_VFracturedWell->setWellCode(pWellData->getCode());
nmDataAttribute tempAttr = m_VFracturedWell->getX();
tempAttr.setValue(pWellData->getLocationX());
m_VFracturedWell->setX(tempAttr);
@ -393,6 +395,7 @@ void nmGuiPlot::initDefultGeoObj()
}
m_HFracturedWell->setWellName(pWellData->getName());
m_HFracturedWell->setWellCode(pWellData->getCode());
nmDataAttribute tempAttr = m_HFracturedWell->getX();
tempAttr.setValue(pWellData->getLocationX());
m_HFracturedWell->setX(tempAttr);
@ -423,6 +426,8 @@ void nmGuiPlot::initDefultGeoObj()
}
// 重新获取添加后的井数据
nmDataAnalyzeManager::getCurrentInstance()->appendNmWellData(
nmDataAnalyzeManager::getCurrentInstance()->getCurWellData());
vecWellDatas = nmDataAnalyzeManager::getCurrentInstance()->getWellDataList();
}

@ -1,4 +1,4 @@
#include "nmPlotGraphicBinder.h"
#include "nmPlotGraphicBinder.h"
#include "nmObjLineFault.h"
#include "nmDataFault.h"
@ -1557,6 +1557,7 @@ bool nmPlotGraphicBinder::ensureSelectedWellData(nmObjPointWell* pGraphic,
// 重新勾选井时在这里补建nmDataWell并将工程树中的基础属性同步进去。
pData->setWellName(pWellData->getName());
pData->setWellCode(pWellData->getCode());
nmDataAttribute tempAttr = pData->getX();
tempAttr.setValue(pWellData->getLocationX());
pData->setX(tempAttr);
@ -1636,6 +1637,12 @@ bool nmPlotGraphicBinder::ensureSelectedWellData(nmObjPointWell* pGraphic,
pData->setHistoryPressure(vvecHistoryPressureData);
pData->setHistoryLogLog(vvecHistoryLogData);
pData->setHistorySemiLog(vvecHistorySemiLogData);
// 通知 PEBI 面板新增井分组
if (m_pDataMgr) {
m_pDataMgr->appendNmWellData(pData);
}
return true;
}
@ -1668,6 +1675,8 @@ bool nmPlotGraphicBinder::editWellForGraphic(nmObjPointWell* pGraphic,
return false;
}
// 类型切换会创建新的数值井对象,井编码仍以工程树数据为准。
pReturnWellData->setWellCode(pWellData->getCode());
pWellData->setName(pReturnWellData->getWellName());
pGraphic->setName(pReturnWellData->getWellName());
pWellData->setLocationX(pReturnWellData->getX().getValue().toDouble());

@ -39,6 +39,7 @@
#include "ZxObjBase.h"
#include "nmDataAnalyzeManager.h"
#include "nmDataWellBase.h"
#include "nmAttrRegistry.h"
#include "iRibbonXmlTab.h"
#include "nmWxParameterProperty.h"
@ -360,6 +361,21 @@ bool nmSubWndUtils::dealwithRibbonTab(iRibbonXmlTab* pTab, \
return false; //your own codes
}
void nmSubWndUtils::connectWellListSignals(nmDataAnalyzeManager* pDataManager,
nmWxParaPropertyPebi* pParaWx)
{
if (!pDataManager || !pParaWx)
return;
// 使用 Qt::UniqueConnection 防止重复连接
QObject::connect(pDataManager, SIGNAL(sigWellAdded(QString,QString,QStringList)),
pParaWx, SLOT(slotWellAdded(QString,QString,QStringList)),
Qt::UniqueConnection);
QObject::connect(pDataManager, SIGNAL(sigWellRemoved(QString,QString)),
pParaWx, SLOT(slotWellRemoved(QString,QString)),
Qt::UniqueConnection);
}
bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
{
iSubWndFitting* pSubWndF = dynamic_cast<iSubWndFitting*>(pSubWnd);
@ -431,7 +447,7 @@ bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
// 1.3 初始化当前井数据
pDataManager->initCurWellData();
// 注册井参数到 nmAttrRegistry必须在 initCurWellData 之后,面板构建之前)
pDataManager->registerWellAttrs();
pDataManager->syncWellAttrs();
// 1.4 初始化边界数据
nmDataWellBase* pCurWell = pDataManager->getCurWellData();
Q_ASSERT(nullptr != pCurWell);
@ -589,42 +605,11 @@ bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
nmWxNumericalDesign* pAnalWx = new nmWxNumericalDesign();
nmWxParaPropertyPebi* pParaWx = new nmWxParaPropertyPebi();
pParaWx->initUI();
QStringList listParas;
listParas << "h" << "Pi" << "K" << "phi" << "Cti" << "Cf" << "Soi" << "Swi";
// 从数据层动态组装井参数
QVector<nmDataWellBase*> listWells = pDataManager->getWellDataList();
QMap<QString, QString> mapWellNames;
foreach (nmDataWellBase* pWell, listWells)
{
QString sCode = pWell->getWellCode();
if (sCode.isEmpty())
continue;
mapWellNames[sCode] = pWell->getWellName();
listParas << sCode + "_W_X";
listParas << sCode + "_W_Y";
listParas << sCode + "_W_Rw";
listParas << sCode + "_W_C";
// Skin 来自第一个射孔段
if (pWell->getPerforationCount() > 0)
{
listParas << sCode + "_W_Skin";
}
}
pParaWx->refreshUIs(listParas, true, mapWellNames);
pParaWx->setDataManager(pDataManager);
pParaWx->rebuildAllParas();
// 通过 nmAttrRegistry 批量读取储层参数初始化UI替代逐个 getter 调用)
nmAttrRegistry* pReg = pDataManager->getAttrRegistry();
if (pReg != nullptr)
{
QMap<QString, QVariant> mapInit = pReg->collect(listParas);
pParaWx->restoreOldParas(mapInit);
}
// 双向同步连接UI→Data
if (pReg != nullptr)
@ -653,6 +638,9 @@ bool nmSubWndUtils::fillNmDockWxs(iSubWnd* pSubWnd)
// QTextEdit* pWx1 = new CustomParaWx("This is demo for upper");
// pWx1->...
// 建立井列表变化与参数面板的刷新连接
connectWellListSignals(pDataManager, pParaWx);
Q_ASSERT(nullptr != pAnalWx);
Q_ASSERT(nullptr != pParaWx);
@ -868,7 +856,7 @@ bool nmSubWndUtils::loadRsts(iSubWnd* pSubWnd, \
// 加载本地文件的数据到数据中心里的数据体里含用户选择的模型类型覆盖PVT推导结果
pDataManager->loadNmResult(sDir);
// 注册井参数到 nmAttrRegistry必须在 loadNmResult 之后,面板构建之前)
pDataManager->registerWellAttrs();
pDataManager->syncWellAttrs();
// 切换左侧参数视图
pSubWndF->swapAnaNmDocks(true);
@ -898,41 +886,10 @@ bool nmSubWndUtils::loadRsts(iSubWnd* pSubWnd, \
nmWxNumericalDesign* pAnalWx = new nmWxNumericalDesign();
nmWxParaPropertyPebi* pParaWx = new nmWxParaPropertyPebi();
pParaWx->initUI();
QStringList listParas;
listParas << "h" << "Pi" << "K" << "phi" << "Cti" << "Cf" << "Soi" << "Swi";
// 从数据层动态组装井参数
QVector<nmDataWellBase*> listWells = pDataManager->getWellDataList();
QMap<QString, QString> mapWellNames;
foreach (nmDataWellBase* pWell, listWells)
{
QString sCode = pWell->getWellCode();
if (sCode.isEmpty())
continue;
mapWellNames[sCode] = pWell->getWellName();
listParas << sCode + "_W_X";
listParas << sCode + "_W_Y";
listParas << sCode + "_W_Rw";
listParas << sCode + "_W_C";
// Skin 来自第一个射孔段
if (pWell->getPerforationCount() > 0)
{
listParas << sCode + "_W_Skin";
}
}
pParaWx->refreshUIs(listParas, true, mapWellNames);
pParaWx->setDataManager(pDataManager);
pParaWx->rebuildAllParas();
nmAttrRegistry* pReg = pDataManager->getAttrRegistry();
if (pReg != nullptr)
{
QMap<QString, QVariant> mapInit = pReg->collect(listParas);
pParaWx->restoreOldParas(mapInit);
}
// 建立求解调用连接
connect(pAnalWx, SIGNAL(sigGenerateClicked()),
@ -954,6 +911,9 @@ bool nmSubWndUtils::loadRsts(iSubWnd* pSubWnd, \
// connect(pAnalWx, SIGNAL(sigUpdateWellPlot(nmDataAnalyzeManager*)),
// pSubWndMain, SLOT(slotUpdateWellPlotByDataManager(nmDataAnalyzeManager*)));
// 建立井列表变化与参数面板的刷新连接
connectWellListSignals(pDataManager, pParaWx);
pWxDockNm1->setWidget(pAnalWx);
pWxDockNm2->setWidget(pParaWx);

@ -1,4 +1,4 @@

#include "zxLogInstance.h"
#include "ZxResolutionHelper.h"
#include "zxSysUtils.h"
@ -10,9 +10,38 @@
#include "iGridRowItem.h"
#include "nmGridRowUtils.h"
#include "nmDataAnalyzeManager.h"
#include "nmDataWellBase.h"
#include "nmAttrRegistry.h"
#include <QSet>
#include "nmWxParaPropertyPebi.h"
namespace {
QStringList reservoirParas()
{
return QStringList() << "h" << "Pi" << "K" << "phi"
<< "Cti" << "Cf" << "Soi" << "Swi";
}
QStringList wellParasOf(const QString& wellCode, bool hasPerforation)
{
QStringList paras;
paras << wellCode + "_W_X"
<< wellCode + "_W_Y"
<< wellCode + "_W_Rw";
if (hasPerforation)
{
paras << wellCode + "_W_Skin";
}
paras << wellCode + "_W_C";
return paras;
}
}
nmWxParaPropertyPebi::nmWxParaPropertyPebi(QWidget* parent) :
iDlgBase(parent)
{
@ -20,6 +49,7 @@ nmWxParaPropertyPebi::nmWxParaPropertyPebi(QWidget* parent) :
m_listParas.clear();
m_pGridItemUtils = nullptr;
m_pHelpBox = nullptr;
m_pDataManager = nullptr;
setWindowTitle(tr("Numerical para property"));
}
@ -106,6 +136,7 @@ void nmWxParaPropertyPebi::refreshUIs(QStringList& listParas, bool bReserveOlds
// Clear Old
QVBoxLayout* pLayout = m_pMainLayout;
clearChildrenOfLayout(pLayout, this);
m_pGridItemUtils = nullptr;
// 创建PEBI求解器专用的GridRowUtils
m_pGridItemUtils = new nmGridRowUtils(true);
@ -114,9 +145,6 @@ void nmWxParaPropertyPebi::refreshUIs(QStringList& listParas, bool bReserveOlds
m_pGridItemUtils->setParaSrcTag(s_Nm_Serie);
connect(m_pGridItemUtils, SIGNAL(sigHelpMsg(QString&)),
this, SLOT(slotHelpMsg(QString&)));
// 信号转发nmGridRowUtils::sigParaChanged → nmWxParaPropertyPebi::sigParaChanged
connect(m_pGridItemUtils, SIGNAL(sigParaChanged(QString, QVariant)),
this, SIGNAL(sigParaChanged(QString, QVariant)));
m_pMainLayout->addWidget(m_pGridItemUtils);
m_pGridItemUtils->setWellNames(mapWellNames);
m_pGridItemUtils->buildRowUtils(listParas, false, this);
@ -190,6 +218,49 @@ void nmWxParaPropertyPebi::slotSetParaValue(QString sPara, QVariant o)
setParaValue(sPara, o);
}
void nmWxParaPropertyPebi::slotParaCtrlValueChanged(QString sPara, QVariant o)
{
if (m_bUnableSP)
return;
emit sigParaChanged(sPara, o);
}
void nmWxParaPropertyPebi::rebuildAllParas()
{
if (m_pMainLayout == nullptr || m_pDataManager == nullptr)
return;
m_pDataManager->syncWellAttrs();
QStringList listParas = reservoirParas();
QMap<QString, QString> mapWellNames;
QSet<QString> addedWellCodes;
const QVector<nmDataWellBase*> wells = m_pDataManager->getWellDataList();
foreach (nmDataWellBase* pWell, wells)
{
if (pWell == nullptr)
continue;
const QString sCode = pWell->getWellCode();
if (sCode.isEmpty() || addedWellCodes.contains(sCode))
continue;
addedWellCodes.insert(sCode);
mapWellNames[sCode] = pWell->getWellName();
listParas << wellParasOf(sCode, pWell->getPerforationCount() > 0);
}
refreshUIs(listParas, false, mapWellNames);
nmAttrRegistry* pReg = m_pDataManager->getAttrRegistry();
if (pReg)
{
QMap<QString, QVariant> values = pReg->collect(listParas);
restoreOldParas(values);
}
}
bool nmWxParaPropertyPebi::getParaValue(QString sPara, QVariant& o)
{
if (nullptr != m_pGridItemUtils)
@ -254,7 +325,14 @@ void nmWxParaPropertyPebi::onDeserialize(ZxSerializer* ser)
m_listParas.clear();
ser->read("ParaLists", m_listParas);
refreshUIs(m_listParas);
if (m_pDataManager != nullptr)
{
rebuildAllParas();
}
else
{
refreshUIs(m_listParas);
}
if (nullptr != m_pGridItemUtils)
{
@ -278,3 +356,18 @@ void nmWxParaPropertyPebi::paintEvent(QPaintEvent* e)
{
iDlgBase::paintEvent(e);
}
void nmWxParaPropertyPebi::slotWellAdded(QString wellCode, QString wellName, QStringList paras)
{
Q_UNUSED(wellCode);
Q_UNUSED(wellName);
Q_UNUSED(paras);
rebuildAllParas();
}
void nmWxParaPropertyPebi::slotWellRemoved(QString wellCode, QString wellName)
{
Q_UNUSED(wellCode);
Q_UNUSED(wellName);
rebuildAllParas();
}

Loading…
Cancel
Save