#include "nmWxEditWellPlot.h" #include "nmWxNumericalDesign.h" #include "nmWxParameterProperty.h" // 包含所有需要的Qt布局和控件头文件 #include #include #include #include #include #include #include #include #include #include #include #include "iWxWellNew.h" #include "ZxDataWell.h" #include "zxSysUtils.h" #include "nmDataWellBase.h" #include "nmDataVerticalWell.h" #include "nmDataVerticalFracturedWell.h" #include "nmDataHorizontalFracturedWell.h" #include "nmWxWellboreTrajectoryDisplay.h" #include "nmWxTimeDependentSkin.h" #include "nmGUIComponentBase.h" // 基础组件类 #include "nmGUIComponentLineEdit.h" // 用于QLineEdit类型的参数 #include "nmGUIComponentComboBox.h" // 用于QComboBox类型的参数 #include "nmWellEditorController.h" nmWxEditWellPlot::nmWxEditWellPlot(QWidget *parent, ZxDataWell* pZxDataWell, nmDataWellBase* pNmDataWell) : QDialog(parent) , m_pMainSplitter(nullptr) , m_pTopVLayout(nullptr) , m_pLeftVLayout(nullptr) , m_pWellNameLineEdit(nullptr) , m_pWellTypeComboBox(nullptr) , m_pWellNewWidget(nullptr) , m_pBottomLeftPanel(nullptr) , m_pRightPanel(nullptr) , m_pOverallBottomPanel(nullptr) , m_pZxDataWell(pZxDataWell) , m_pNmDataWell(nullptr) , m_pWellEditorController(nullptr) , m_bOriginalTimeDependentSkin(false) { // 设置新的数据,并创建其深拷贝 if(pNmDataWell) { // 保存原始状态 m_bOriginalTimeDependentSkin = pNmDataWell->isTimeDependentSkin(); // 返回深拷贝对象。 m_pNmDataWell = pNmDataWell->clone(); // 数据模型变化时,刷新左侧参数面板 connect(m_pNmDataWell, SIGNAL(sigParameterChanged()), this, SLOT(onWellDataChanged())); } // 初始化图标路径 m_sIconDir = QCoreApplication::applicationDirPath(); m_sIconDir = m_sIconDir.section('/', 0, -2); // 获取上一级目录 m_sIconDir += "/Res/Icon/"; this->resize(1121, 633); // 调用初始化UI的方法 this->initUI(); // 创建控制器 if(m_pNmDataWell && m_pRightPanel) { m_pWellEditorController = new nmWellEditorController(m_pNmDataWell, m_pRightPanel, this); // 将当前对话框作为父对象 setupControllerConnections(); // 调用连接设置函数 } } nmWxEditWellPlot::~nmWxEditWellPlot() { // 在析构函数中清理所有动态创建的组件,避免内存泄漏 qDeleteAll(m_listParameterComponents); m_listParameterComponents.clear(); // 清空列表 } void nmWxEditWellPlot::initUI() { this->initMainLayout(); // 在所有UI元素创建完成后,根据井类型初始化底部左侧面板 // 注意:m_pBottomLeftGridLayout 必须在这里之前被 createLeftPanel() 创建 updateBottomLeftPanelUI(); } void nmWxEditWellPlot::initMainLayout() { // 创建左侧和右侧面板 QWidget* pLeftContainer = createLeftPanel(); QWidget* pRightPanelWidget = createRightPanel(); // 创建主分割器并添加左右面板 m_pMainSplitter = new QSplitter(Qt::Horizontal, this); m_pMainSplitter->addWidget(pLeftContainer); m_pMainSplitter->addWidget(pRightPanelWidget); // 设置分割器的初始大小比例 QList sizes; sizes << 373 << 748; m_pMainSplitter->setSizes(sizes); // 创建底部面板 QWidget* pBottomPanel = createBottomPanel(); // 创建顶层垂直布局并添加分割器和底部面板 m_pTopVLayout = new QVBoxLayout(this); m_pTopVLayout->setContentsMargins(0, 0, 0, 0); m_pTopVLayout->setSpacing(0); m_pTopVLayout->addWidget(m_pMainSplitter, 1); // 分割器可拉伸 m_pTopVLayout->addWidget(pBottomPanel, 0); // 底部面板固定高度,不拉伸 this->setLayout(m_pTopVLayout); // 将此布局设置为对话框的主布局 } QWidget* nmWxEditWellPlot::createLeftPanel() { //m_pLeftVLayout = new QVBoxLayout(); //m_pLeftVLayout->setContentsMargins(0, 0, 0, 0); //m_pLeftVLayout->setSpacing(5); //// 井视图部分 (iWxWellNew) 保持不变 //m_pWellNewWidget = new iWxWellNew(this); //m_pWellNewWidget->setDataWell(m_pZxDataWell); //m_pWellNewWidget->setActionMode(DAM_Edit); //m_pWellNewWidget->initUI(); //m_pWellNewWidget->setWindowFlags(Qt::Widget); //m_pLeftVLayout->addWidget(m_pWellNewWidget, 1); //// 1. 创建 m_pBottomLeftPanel (作为 QScrollArea 的容器) //m_pBottomLeftPanel = new QWidget(this); // 确保它有父对象 //m_pBottomLeftPanel->setStyleSheet("background-color: white;"); //// 2. 在 m_pBottomLeftPanel 内部创建一个垂直布局来容纳 QScrollArea //QVBoxLayout* pBottomLeftPanelVLayout = new QVBoxLayout(m_pBottomLeftPanel); //pBottomLeftPanelVLayout->setContentsMargins(0, 0, 0, 0); // 内部布局边距 //pBottomLeftPanelVLayout->setSpacing(0); // 内部布局间距 //// 3. 创建 QScrollArea 并设置其父对象为 m_pBottomLeftPanel //QScrollArea* pScrollArea = new QScrollArea(m_pBottomLeftPanel); //pScrollArea->setWidgetResizable(true); // 允许滚动区域调整其内部控件的大小 //// 4. 创建一个 QWidget 作为滚动区域的内容容器 //QWidget* pScrollContent = new QWidget(pScrollArea); // 父对象是 pScrollArea //// 5. 将 m_pBottomLeftGridLayout 设置为 pScrollContent 的布局 //m_pBottomLeftGridLayout = new QGridLayout(pScrollContent); //m_pBottomLeftGridLayout->setContentsMargins(10, 10, 10, 10); // 网格布局的边距 //m_pBottomLeftGridLayout->setSpacing(8); //m_pBottomLeftGridLayout->setColumnStretch(0, 1); // 标签列 //m_pBottomLeftGridLayout->setColumnStretch(1, 2); // 值输入列 //// 6. 将 pScrollContent 设置为滚动区域的内容控件 //pScrollArea->setWidget(pScrollContent); //// 7. 将滚动区域添加到 m_pBottomLeftPanel 的内部布局中 //pBottomLeftPanelVLayout->addWidget(pScrollArea); //// 将 m_pBottomLeftPanel (现在包含了滚动区域) 添加到左侧主垂直布局 //m_pLeftVLayout->addWidget(m_pBottomLeftPanel, 1); // 占据垂直布局的1份空间 //// 创建一个 QWidget 来承载左侧的垂直布局 //QWidget* pLeftContainer = new QWidget(this); //pLeftContainer->setLayout(m_pLeftVLayout); //pLeftContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //return pLeftContainer; m_pLeftVLayout = new QVBoxLayout(); m_pLeftVLayout->setContentsMargins(0, 0, 0, 0); m_pLeftVLayout->setSpacing(5); // 1. 创建 m_pBottomLeftPanel (作为 QScrollArea 的容器) m_pBottomLeftPanel = new QWidget(this); // 确保它有父对象 m_pBottomLeftPanel->setStyleSheet("background-color: white;"); // 2. 在 m_pBottomLeftPanel 内部创建一个垂直布局来容纳 QScrollArea QVBoxLayout* pBottomLeftPanelVLayout = new QVBoxLayout(m_pBottomLeftPanel); pBottomLeftPanelVLayout->setContentsMargins(0, 0, 0, 0); // 内部布局边距 pBottomLeftPanelVLayout->setSpacing(0); // 内部布局间距 // 3. 创建 QScrollArea 并设置其父对象为 m_pBottomLeftPanel QScrollArea* pScrollArea = new QScrollArea(m_pBottomLeftPanel); pScrollArea->setWidgetResizable(true); // 允许滚动区域调整其内部控件的大小 // 4. 创建一个 QWidget 作为滚动区域的内容容器 QWidget* pScrollContent = new QWidget(pScrollArea); // 父对象是 pScrollArea // 5. 将 m_pBottomLeftGridLayout 设置为 pScrollContent 的布局 m_pBottomLeftGridLayout = new QGridLayout(pScrollContent); m_pBottomLeftGridLayout->setContentsMargins(10, 10, 10, 10); // 网格布局的边距 m_pBottomLeftGridLayout->setSpacing(8); m_pBottomLeftGridLayout->setColumnStretch(0, 1); // 标签列 m_pBottomLeftGridLayout->setColumnStretch(1, 2); // 值输入列 // 6. 将 pScrollContent 设置为滚动区域的内容控件 pScrollArea->setWidget(pScrollContent); // 7. 将滚动区域添加到 m_pBottomLeftPanel 的内部布局中 pBottomLeftPanelVLayout->addWidget(pScrollArea); // 将 m_pBottomLeftPanel (现在包含了滚动区域) 添加到左侧主垂直布局 m_pLeftVLayout->addWidget(m_pBottomLeftPanel, 1); // 占据垂直布局的1份空间 // 创建一个 QWidget 来承载左侧的垂直布局 QWidget* pLeftContainer = new QWidget(this); pLeftContainer->setLayout(m_pLeftVLayout); pLeftContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); return pLeftContainer; } QWidget* nmWxEditWellPlot::createRightPanel() { m_pRightPanel = new nmWxWellboreTrajectoryDisplay(this); m_pRightPanel->setContentsMargins(0, 0, 0, 0); // 可以设置外部边距 m_pRightPanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // 设置井数据 m_pRightPanel->setCurrentWellboreData(m_pNmDataWell); return m_pRightPanel; } QWidget* nmWxEditWellPlot::createBottomPanel() { m_pOverallBottomPanel = new QWidget(this); m_pOverallBottomPanel->setFixedHeight(80); // 增加高度以容纳两行内容 QVBoxLayout* mainBottomVLayout = new QVBoxLayout(m_pOverallBottomPanel); mainBottomVLayout->setContentsMargins(5, 5, 5, 5); mainBottomVLayout->setSpacing(5); // 第一行:原有的控件 QWidget* hContentContainer = new QWidget(m_pOverallBottomPanel); QHBoxLayout* bottomContentHLayout = new QHBoxLayout(hContentContainer); bottomContentHLayout->setContentsMargins(0, 0, 0, 0); bottomContentHLayout->setSpacing(10); QCheckBox* myCheckBox = new QCheckBox("Use in multiple well modes", hContentContainer); QComboBox* myComboBox = new QComboBox(hContentContainer); myComboBox->addItem("Tested well"); myComboBox->addItem("well_1"); myComboBox->addItem("well_2"); QPushButton* pOKButton = new QPushButton("OK", hContentContainer); QPushButton* pCancelButton = new QPushButton("Cancel", hContentContainer); bottomContentHLayout->addWidget(myCheckBox); bottomContentHLayout->addWidget(myComboBox); bottomContentHLayout->addStretch(); bottomContentHLayout->addWidget(pOKButton); bottomContentHLayout->addWidget(pCancelButton); // 连接按钮到自定义槽函数 (Qt 4 语法) connect(pOKButton, SIGNAL(clicked()), this, SLOT(onOkClicked())); connect(pCancelButton, SIGNAL(clicked()), this, SLOT(onCancelClicked())); // 第二行:时间相关复选框和关联的时钟图标按钮 QWidget* timeContainer = new QWidget(m_pOverallBottomPanel); QHBoxLayout* pTimeDependentLayout = new QHBoxLayout(timeContainer); pTimeDependentLayout->setContentsMargins(0, 0, 0, 0); pTimeDependentLayout->setSpacing(5); m_pTimeDependentCheck = new QCheckBox(tr("Time dependent"), timeContainer); m_pTimeDependentCheck->setChecked(m_pNmDataWell->isTimeDependentSkin()); m_pTimeDependentIconButton = new QPushButton(timeContainer); m_pTimeDependentIconButton->setIcon(QIcon(m_sIconDir + "NmAnalDesign3.png")); // 使用时钟图标 m_pTimeDependentIconButton->setIconSize(QSize(20, 20)); m_pTimeDependentIconButton->setFixedSize(22, 22); m_pTimeDependentIconButton->setEnabled(m_pNmDataWell->isTimeDependentSkin()); pTimeDependentLayout->addWidget(m_pTimeDependentCheck); pTimeDependentLayout->addWidget(m_pTimeDependentIconButton); pTimeDependentLayout->addStretch(); // 添加拉伸器,将它们推到左侧 // 连接复选框状态变化信号到槽函数 connect(m_pTimeDependentCheck, SIGNAL(toggled(bool)), m_pTimeDependentIconButton, SLOT(setEnabled(bool))); connect(m_pTimeDependentIconButton, SIGNAL(clicked()), this, SLOT(onTimeDependentIconClicked())); connect(m_pTimeDependentCheck, SIGNAL(toggled(bool)), this, SLOT(onTimeDependentCheckToggled(bool))); // 将两行内容添加到主垂直布局 mainBottomVLayout->addWidget(hContentContainer); mainBottomVLayout->addWidget(timeContainer); return m_pOverallBottomPanel; } void nmWxEditWellPlot::setupControllerConnections() { if(!m_pWellEditorController || !m_pRightPanel || !m_pNmDataWell) { return; } // --- 1. nmWxWellboreTrajectoryDisplay (视图) 发出的模式请求信号连接到控制器 --- // 这些信号会在用户点击工具栏按钮时发出 connect(m_pRightPanel, SIGNAL(requestedEditWellMode(int)), m_pWellEditorController, SLOT(onRequestEditWellMode(int))); connect(m_pRightPanel, SIGNAL(requestedEditPerforationsMode(int)), m_pWellEditorController, SLOT(onRequestEditPerforationsMode(int))); connect(m_pRightPanel, SIGNAL(requestedNewPerforationMode(int)), m_pWellEditorController, SLOT(onRequestNewPerforationMode(int))); connect(m_pRightPanel, SIGNAL(requestedDeletePerforationMode(int)), m_pWellEditorController, SLOT(onRequestDeletePerforationMode(int))); connect(m_pRightPanel, SIGNAL(requestedSnapPerforationMode(int)), m_pWellEditorController, SLOT(onRequestSnapPerforationMode(int))); connect(m_pRightPanel, SIGNAL(sigClearViewStates()), m_pWellEditorController, SLOT(slotClearViewStates())); // --- 2. nmWxWellboreTrajectoryDisplay (视图) 发出的视图切换信号连接到控制器 --- connect(m_pRightPanel, SIGNAL(currentViewChanged(int)), m_pWellEditorController, SLOT(onViewChanged(int))); // 井筒点移动信号到控制器 (只在拖动结束时触发) connect(m_pRightPanel, SIGNAL(sigWellboreTrajectoryPointMoved(QPointF)), m_pWellEditorController, SLOT(slotWellboreTrajectoryPointMoved(QPointF))); // 射孔拖动信号到控制器 (只在拖动结束时触发) connect(m_pRightPanel, SIGNAL(sigPerforationDragFinished(nmDataPerforation*, double, double)), m_pWellEditorController, SLOT(slotPerforationDragFinished(nmDataPerforation*, double, double))); // 射孔添加模式,发送给控制器 connect(m_pRightPanel, SIGNAL(sigTryAddNewPerforation(QPointF, double, double, QLineF)), m_pWellEditorController, SLOT(slotTryAddNewPerforation(QPointF, double, double, QLineF))); // 射孔删除模式 connect(m_pRightPanel, SIGNAL(sigTryDeletePerforation(nmDataPerforation*)), m_pWellEditorController, SLOT(slotDeletePerforation(nmDataPerforation*))); // 更新裂缝俯视位置 connect(m_pRightPanel, SIGNAL(sigFractureGeometryDragFinished(double, double)), m_pWellEditorController, SLOT(slotFractureGeometryChanged(double, double))); // 连接截面图下更新裂缝位置的信号槽 connect(m_pRightPanel, SIGNAL(sigRequestFractureRectUpdate(qreal, qreal)), m_pWellEditorController, SLOT(slotHandleFractureRectUpdate(qreal, qreal))); // 射孔更新 connect(m_pRightPanel, SIGNAL(sigFractureDragFinished(const QMap>&)), m_pWellEditorController, SLOT(slotUpdatePerforations(const QMap>&))); // 裂缝半长更新 connect(m_pRightPanel, SIGNAL(sigFractureHalfLengthChanged(double)), m_pWellEditorController, SLOT(slotUpdateFractureHalfLength(double))); // 井身位置更新 connect(m_pRightPanel, SIGNAL(sigWellboreDragFinished(QPointF)), m_pWellEditorController, SLOT(slotUpdateWellborePos(QPointF))); // 多段压裂水平井截面图裂缝位置更新 connect(m_pRightPanel, SIGNAL(sigFractureGeometryChanged(double, double)), m_pWellEditorController, SLOT(slotHFWellFractureGeometryChanged(double, double))); } void nmWxEditWellPlot::updateBottomLeftPanelUI() { if(!m_pNmDataWell || !m_pBottomLeftGridLayout) { qDebug() << "nmDataWellBase pointer or m_pBottomLeftGridLayout is null in updateBottomLeftPanelUI!"; return; } // 1. 清空当前网格布局中的所有控件 // 并从 m_listParameterComponents 中删除并释放所有组件 QLayoutItem *item; while((item = m_pBottomLeftGridLayout->takeAt(0)) != nullptr) { if(item->widget()) { // 从 m_listParameterComponents 中移除并删除对应的组件 nmGUIComponentBase* component = qobject_cast(item->widget()); if(component) { m_listParameterComponents.removeOne(component); // 从列表中移除 // component->deleteLater(); // item->widget() 会处理删除 } item->widget()->deleteLater(); // 删除Qt控件 } delete item; // 删除布局项 } m_listParameterComponents.clear(); // 确保列表清空 int currentRow = 0; // 用于跟踪当前添加控件的行数 // 2. 添加井名称的 QLabel 和 QLineEdit m_pWellNameLineEdit = nullptr; QLabel* pWellNameLabel = new QLabel(tr("Well Name:"), this); // 使用成员变量 m_pWellNameLineEdit,确保在槽函数中可以访问 m_pWellNameLineEdit = new QLineEdit(this); m_pWellNameLineEdit->setText(m_pNmDataWell->getWellName()); // 连接编辑框的编辑完成信号到槽函数 connect(m_pWellNameLineEdit, SIGNAL(editingFinished()), this, SLOT(onWellNameEditingFinished())); m_pBottomLeftGridLayout->addWidget(pWellNameLabel, currentRow, 0, 1, 1); m_pBottomLeftGridLayout->addWidget(m_pWellNameLineEdit, currentRow, 1, 1, 1); currentRow++; // 行号递增 // 3. 创建并添加 QLabel 和 QComboBox m_pWellTypeComboBox = nullptr; QLabel* pWellTypeLabel = new QLabel(tr("Well Type:"), this); m_pWellTypeComboBox = new QComboBox(this); m_pWellTypeComboBox->addItem(tr("Vertical Well"), NM_WELL_MODEL::Vertical_Well); m_pWellTypeComboBox->addItem(tr("Vertical Fractured Well"), NM_WELL_MODEL::Vertical_Fractured_Well); m_pWellTypeComboBox->addItem(tr("Horizontal Fractured Well"), NM_WELL_MODEL::Horizontal_Fractured_Well); // 重新连接信号槽 connect(m_pWellTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onWellTypeChanged(int))); // 4. 根据当前 m_pNmDataWell 的类型设置选中项 NM_WELL_MODEL currentType = m_pNmDataWell->getWellType(); int index = m_pWellTypeComboBox->findData(currentType); if(index != -1) { m_pWellTypeComboBox->setCurrentIndex(index); } // 5. 将 QLabel 和 QComboBox 添加到布局 m_pBottomLeftGridLayout->addWidget(pWellTypeLabel, currentRow, 0, 1, 1); m_pBottomLeftGridLayout->addWidget(m_pWellTypeComboBox, currentRow, 1, 1, 1); currentRow++; // 6. 根据井类型动态添加参数 // 这里使用 dynamic_cast 来判断具体的井类型并访问其特有属性 // 井的通用参数(所有井类型都可能有的) // Location---位置 // addLineEditComponentToGrid(m_pNmDataWell->getInputWellHead(), currentRow); // addLineEditComponentToGrid(m_pNmDataWell->getWellHeadX(), currentRow); // addLineEditComponentToGrid(m_pNmDataWell->getWellHeadY(), currentRow); addLineEditComponentToGrid(m_pNmDataWell->getX(), currentRow); addLineEditComponentToGrid(m_pNmDataWell->getY(), currentRow); // Geometry and properties---几何与属性 addLineEditComponentToGrid(m_pNmDataWell->getDrillFloorElevation(), currentRow); addLineEditComponentToGrid(m_pNmDataWell->getRadius(), currentRow); addLineEditComponentToGrid(m_pNmDataWell->getZw(), currentRow); addLineEditComponentToGrid(m_pNmDataWell->getWellLength(), currentRow); // addLineEditComponentToGrid(m_pNmDataWell->getRateDependentSkin(), currentRow); addLineEditComponentToGrid(m_pNmDataWell->getdSdQ(), currentRow); // Wellbore---井储 addComboBoxComponentToGrid(m_pNmDataWell->getWellboreModel(), currentRow); addLineEditComponentToGrid(m_pNmDataWell->getWellboreStorage(), currentRow); addLineEditComponentToGrid(m_pNmDataWell->getFinalWellboreStorage(), currentRow); addLineEditComponentToGrid(m_pNmDataWell->getCInitialCFinal(), currentRow); addLineEditComponentToGrid(m_pNmDataWell->getDtChangingStorage(), currentRow); addLineEditComponentToGrid(m_pNmDataWell->getLeakSkin(), currentRow); // Bottomhole conditions---井底条件 addLineEditComponentToGrid(m_pNmDataWell->getBottomholeMD(), currentRow); // 射孔段的表皮系数(如果井有射孔段) if(m_pNmDataWell->getPerforationCount() > 0) { for(int i = 0; i < m_pNmDataWell->getPerforationCount(); ++i) { nmDataPerforation* perforation = m_pNmDataWell->getPerforation(i); if(perforation) { addLineEditComponentToGrid(perforation->getName(), currentRow); addLineEditComponentToGrid(perforation->getMdStart(), currentRow); addLineEditComponentToGrid(perforation->getMdEnd(), currentRow); addLineEditComponentToGrid(perforation->getSkin(), currentRow); } } } // 根据具体的井模型添加特有参数 if(nmDataVerticalFracturedWell * pVFWell = dynamic_cast(m_pNmDataWell)) { // 垂直裂缝井特有参数 addVerticalFracturedWellParameters(pVFWell, currentRow); // 委托给私有辅助函数 } else if(nmDataHorizontalFracturedWell * pHFWell = dynamic_cast(m_pNmDataWell)) { // 多段压裂水平井特有参数 addHorizontalFracturedWellParameters(pHFWell, currentRow); // 委托给私有辅助函数 } else if(nmDataVerticalWell * pVWell = dynamic_cast(m_pNmDataWell)) { // 直井特有参数 addVerticalWellParameters(pVWell, currentRow); // 委托给私有辅助函数 } // 强制刷新布局和调整面板大小 // m_pBottomLeftGridLayout->update(); // m_pBottomLeftPanel->adjustSize(); // 调整面板大小以适应新内容 } // 辅助函数:向网格布局中添加 nmGUIComponentLineEdit void nmWxEditWellPlot::addLineEditComponentToGrid(nmDataAttribute& attribute, int& row) { // const_cast 是安全的,因为 nmGUIComponentLineEdit 内部会操作 nmDataAttribute 的非 const 引用, // 而这个引用在 nmDataWell 对象内部是可修改的。 nmGUIComponentLineEdit* component = new nmGUIComponentLineEdit(const_cast(&attribute), true, m_pBottomLeftPanel); // 设置实时更新数据 component->setIsRealTimeUpdateValue(true); m_listParameterComponents.append(component); // 添加到管理列表中 m_pBottomLeftGridLayout->addWidget(component, row, 0, 1, 2); // 跨两列 row++; // 行号递增 } // 辅助函数:向网格布局中添加 nmGUIComponentComboBox void nmWxEditWellPlot::addComboBoxComponentToGrid(nmDataAttribute& attribute, int& row) { nmGUIComponentComboBox* component = new nmGUIComponentComboBox(const_cast(&attribute), true, m_pBottomLeftPanel); m_listParameterComponents.append(component); // 添加到管理列表中 m_pBottomLeftGridLayout->addWidget(component, row, 0, 1, 2); // 跨两列 row++; // 行号递增 } // 私有辅助函数:添加垂直井特有参数 void nmWxEditWellPlot::addVerticalWellParameters(nmDataVerticalWell* well, int& row) { if(!well) return; // 添加垂直井特有的参数 addLineEditComponentToGrid(well->getPerforationLength(), row); } // 私有辅助函数:添加垂直压裂井特有参数 void nmWxEditWellPlot::addVerticalFracturedWellParameters(nmDataVerticalFracturedWell* well, int& row) { if(!well) return; // 添加垂直压裂井特有的参数 addComboBoxComponentToGrid(well->getFractureModel(), row); addLineEditComponentToGrid(well->getFractureHalfLength(), row); addLineEditComponentToGrid(well->getFractureHeight(), row); addLineEditComponentToGrid(well->getFractureMidPointHeight(), row); addLineEditComponentToGrid(well->getWidth(), row); addLineEditComponentToGrid(well->getFractureAngle(), row); addLineEditComponentToGrid(well->getDfc(), row); } // 私有辅助函数:添加水平压裂井特有参数 void nmWxEditWellPlot::addHorizontalFracturedWellParameters(nmDataHorizontalFracturedWell* well, int& row) { if(!well) return; // 添加水平压裂井特有的参数 addLineEditComponentToGrid(well->getDrainAngle(), row); addComboBoxComponentToGrid(well->getModelingType(), row); addComboBoxComponentToGrid(well->getFractureModel(), row); addLineEditComponentToGrid(well->getNumberOfFractures(), row); addLineEditComponentToGrid(well->getFractureHalfLength(), row); addLineEditComponentToGrid(well->getFractureHeight(), row); addLineEditComponentToGrid(well->getFractureMidPointHeight(), row); addLineEditComponentToGrid(well->getWidth(), row); addLineEditComponentToGrid(well->getFractureAngle(), row); addLineEditComponentToGrid(well->getStimulatedZonesAroundFracture(), row); addLineEditComponentToGrid(well->getStimulationRadius(), row); addLineEditComponentToGrid(well->getPermeabilityMultiplier(), row); addLineEditComponentToGrid(well->getPorosityMultiplier(), row); addLineEditComponentToGrid(well->getDfc(), row); } nmDataWellBase* nmWxEditWellPlot::getModifiedDataWell() { return m_pNmDataWell; } void nmWxEditWellPlot::onOkClicked() { if(!m_pNmDataWell) { qDebug() << "nmDataWellBase pointer is null in onOkClicked!"; QDialog::reject(); return; } // 应用时间变表皮状态到真实数据 nmDataWellBase* pRealWell = nmDataAnalyzeManager::getCurrentInstance()->getCurWellData(); if(pRealWell && pRealWell->getWellName() == m_pNmDataWell->getWellName()) { pRealWell->setTimeDependentSkin(m_pNmDataWell->isTimeDependentSkin()); } nmDataAnalyzeManager* manager = nmDataAnalyzeManager::getCurrentInstance(); NM_WELL_MODEL currentWellType = m_pNmDataWell->getWellType(); // 根据井类型调用对应的update方法 if(currentWellType == NM_WELL_MODEL::Vertical_Well) { // 转换为垂直井类型 if(auto * verticalWell = dynamic_cast(m_pNmDataWell)) { QVector wells; wells.append(*verticalWell); // 添加井的副本到QVector中 manager->updateVerticalWells(wells); } } else if(currentWellType == NM_WELL_MODEL::Vertical_Fractured_Well) { // 转换为垂直压裂井类型 if(auto * verticalFracturedWell = dynamic_cast(m_pNmDataWell)) { QVector wells; wells.append(*verticalFracturedWell); // 添加井的副本到QVector中 manager->updateVerticalFracturedWells(wells); } } else if(currentWellType == NM_WELL_MODEL::Horizontal_Fractured_Well) { // 转换为水平压裂井类型 if(auto * horizontalFracturedWell = dynamic_cast(m_pNmDataWell)) { QVector wells; wells.append(*horizontalFracturedWell); // 添加井的副本到QVector中 manager->updateHorizontalFracturedWells(wells); } } else { QDialog::reject(); return; } // 更新完成后,通知参数界面刷新 nmWxParameterProperty::notifyUpdateTable(); accept(); } void nmWxEditWellPlot::onCancelClicked() { if(m_pNmDataWell) { nmWxNumericalDesign::notifyTimeDependentSkinChanged(m_pNmDataWell->getWellName(), m_bOriginalTimeDependentSkin); delete m_pNmDataWell; m_pNmDataWell = nullptr; } reject(); } void nmWxEditWellPlot::onWellDataChanged() { // 重新加载所有参数,将模型中的新值显示在UI上 updateBottomLeftPanelUI(); } void nmWxEditWellPlot::onWellTypeChanged(int index) { // 1. 获取选择的井类型枚举值 // 使用 itemData() 方法获取在 addItem() 时关联的枚举值 QVariant selectedData = m_pWellTypeComboBox->itemData(index); if(!selectedData.isValid()) { return; } NM_WELL_MODEL newWellType = static_cast(selectedData.toInt()); // 2. 获取当前井的类型 NM_WELL_MODEL currentWellType = m_pNmDataWell->getWellType(); // 3. 如果新旧类型相同,则无需操作 if(newWellType == currentWellType) { return; } // 4. 实现核心逻辑:创建新对象、复制数据、销毁旧对象 // 保存旧数据模型的指针 nmDataWellBase* pOldWellData = m_pNmDataWell; // 创建一个新的数据模型对象 nmDataWellBase* pNewWellData = nullptr; if(newWellType == NM_WELL_MODEL::Vertical_Well) { pNewWellData = new nmDataVerticalWell(); pNewWellData->setWellType(Vertical_Well); } else if(newWellType == NM_WELL_MODEL::Vertical_Fractured_Well) { pNewWellData = new nmDataVerticalFracturedWell(); pNewWellData->setWellType(Vertical_Fractured_Well); } else if(newWellType == NM_WELL_MODEL::Horizontal_Fractured_Well) { pNewWellData = new nmDataHorizontalFracturedWell(); pNewWellData->setWellType(Horizontal_Fractured_Well); } else { return; } // 将旧数据中的通用属性复制到新数据中 if(pNewWellData && pOldWellData) { // 通用几何位置 pNewWellData->setWellName(pOldWellData->getWellName()); pNewWellData->setX(pOldWellData->getX()); pNewWellData->setY(pOldWellData->getY()); pNewWellData->setRadius(pOldWellData->getRadius()); // 历史数据 pNewWellData->setPressurePoints(pOldWellData->getPressurePoints()); pNewWellData->setFlowPoints(pOldWellData->getFlowPoints()); pNewWellData->setIndexF(pOldWellData->getIndexF()); // 结果数据 pNewWellData->setResultPressure(pOldWellData->getResultPressure()); pNewWellData->setResultLogLog(pOldWellData->getResultLogLog()); pNewWellData->setResultSemiLog(pOldWellData->getResultSemiLog()); } // 对于裂缝类型的井,需要更新裂缝位置 if(newWellType == NM_WELL_MODEL::Vertical_Fractured_Well) { if(nmDataVerticalFracturedWell * pVFWell = dynamic_cast(pNewWellData)) { pVFWell->setFracs(); } } else if(newWellType == NM_WELL_MODEL::Horizontal_Fractured_Well) { if(nmDataHorizontalFracturedWell * pHFWell = dynamic_cast(pNewWellData)) { pHFWell->setFracs(); } } // 5. 更新 m_pNmDataWell 指针 m_pNmDataWell = pNewWellData; // 6. 重新连接信号:先断开旧连接,再连接新对象 if(pOldWellData) { disconnect(pOldWellData, SIGNAL(sigParameterChanged()), this, SLOT(onWellDataChanged())); } if(m_pNmDataWell) { connect(m_pNmDataWell, SIGNAL(sigParameterChanged()), this, SLOT(onWellDataChanged())); } // 7. 销毁旧控制器并创建新控制器 // 由于控制器是 QObject 的子对象,它会被父对象(this)自动管理内存。 // 但是为了保证逻辑的清晰和安全,我们手动处理。 if(m_pWellEditorController) { delete m_pWellEditorController; m_pWellEditorController = nullptr; } if(m_pNmDataWell && m_pRightPanel) { m_pWellEditorController = new nmWellEditorController(m_pNmDataWell, m_pRightPanel, this); // 重建控制器后,必须重新连接所有信号 setupControllerConnections(); } // 8. 销毁旧数据对象 if(pOldWellData) { delete pOldWellData; } // 9. 刷新 UI updateBottomLeftPanelUI(); // 10. 通知 nmWxWellboreTrajectoryDisplay 视图刷新 if(m_pRightPanel) { m_pRightPanel->setCurrentWellboreData(m_pNmDataWell); // 重新设置数据 } } void nmWxEditWellPlot::onWellNameEditingFinished() { if(m_pNmDataWell && m_pWellNameLineEdit) { // 获取编辑框中的文本并更新数据模型 m_pNmDataWell->setWellName(m_pWellNameLineEdit->text()); } } void nmWxEditWellPlot::keyPressEvent(QKeyEvent *event) { // 如果按下的键是回车键,则忽略它,不调用父类的 keyPressEvent if(event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { // 事件已被处理,阻止它继续传播 event->ignore(); return; } // 对于所有其他按键,调用基类的处理 QDialog::keyPressEvent(event); } void nmWxEditWellPlot::onTimeDependentIconClicked() { if(!m_pNmDataWell) { return; } nmWxTimeDependentSkin::showForCurrentWell(m_pNmDataWell, this); // 传具体井数据 } void nmWxEditWellPlot::onTimeDependentCheckToggled(bool checked) { if(!m_pNmDataWell) { return; } // 更新数据模型 m_pNmDataWell->setTimeDependentSkin(checked); nmWxNumericalDesign::notifyTimeDependentSkinChanged(m_pNmDataWell->getWellName(), checked); }