#include "nmWxIncludeOtherWells.h" #include "nmDataAnalyzeManager.h" #include "nmDataWellBase.h" #include #include #include namespace { // Include 对话框只展示当前 PEBI 网格能够表达的真实井型。 bool isSupportedNumericalWell(nmDataWellBase* pWellData) { if(pWellData == nullptr || pWellData->getWellCode().isEmpty()) { return false; } const NM_WELL_MODEL eWellType = pWellData->getWellType(); return eWellType == NM_WELL_MODEL::Vertical_Well || eWellType == NM_WELL_MODEL::Vertical_Fractured_Well || eWellType == NM_WELL_MODEL::Horizontal_Fractured_Well; } } nmWxIncludeOtherWells::nmWxIncludeOtherWells( nmDataAnalyzeManager* pDataManager, QWidget* pParent) : iDlgBase(pParent), m_pDataManager(pDataManager), m_pTableWidget(nullptr), m_pOkButton(nullptr), m_pCancelButton(nullptr), m_pButtonLayout(nullptr), m_pMainLayout(nullptr) { this->initUI(); } nmWxIncludeOtherWells::~nmWxIncludeOtherWells() { // Qt的对象父子关系会自动处理内存释放 } void nmWxIncludeOtherWells::initUI() { this->setupTable(); this->setupButtons(); this->setupLayouts(); this->setupConnections(); this->setWindowTitle(tr("Include Other Wells")); this->resize(772, 339); } void nmWxIncludeOtherWells::setupTable() { m_pTableWidget = new QTableWidget(this); QVector vecMapWells; if(m_pDataManager != nullptr) { vecMapWells = m_pDataManager->getWellDataList(); } // 设置行列数 m_pTableWidget->setColumnCount(6); m_pTableWidget->setRowCount(vecMapWells.size()); m_pTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); m_pTableWidget->setSelectionMode(QAbstractItemView::SingleSelection); m_pTableWidget->setStyleSheet( "QTableWidget::item:focus {" " background: transparent;" " color: black;" "}" ); // 设置水平表头(列标题) QStringList headers; headers << tr("Name") << tr("Included") << tr("Oil production") << tr("Gas production") << tr("Water production") << tr("Pressure"); m_pTableWidget->setHorizontalHeaderLabels(headers); // 确保水平表头可见 m_pTableWidget->horizontalHeader()->setVisible(true); // 设置垂直表头(行标题)属性 m_pTableWidget->verticalHeader()->setVisible(true); // 保持垂直表头可见(用于行选择视觉反馈) m_pTableWidget->verticalHeader()->setMinimumWidth(16); // 最小宽度 // 隐藏垂直表头的数字(设置为空文本) QStringList emptyRowHeaders; for(int i = 0; i < m_pTableWidget->rowCount(); ++i) { emptyRowHeaders << ""; } m_pTableWidget->setVerticalHeaderLabels(emptyRowHeaders); // 加载数据 QString sPrimaryWellCode = m_pDataManager != nullptr ? m_pDataManager->getPrimaryWellCode() : QString(); int nDisplayRow = 0; // 第一步:候选来源是 Map,而不是整个项目井库。该对话框只管理 // 其他有产量的生产/注入井;主井和无产量观察井都不在这里显示。 for(int i = 0; i < vecMapWells.size(); i++) { nmDataWellBase* pWell = vecMapWells[i]; if(pWell == nullptr || !isSupportedNumericalWell(pWell)) { continue; } const bool bIsPrimary = pWell->getWellCode() == sPrimaryWellCode; const bool bHasValidRate = nmIsValidWellCategory(pWell->getWellCategory()) && pWell->getFlowSegmentCount() > 0; const bool bHasValidPressure = pWell->getPressurePoints().size() >= 2; if(bIsPrimary || !bHasValidRate) { continue; } WellDataRow oWellRow; oWellRow.m_sWellCode = pWell->getWellCode(); oWellRow.m_sName = pWell->getWellName(); oWellRow.m_bIsPrimary = bIsPrimary; oWellRow.m_eWellCategory = pWell->getWellCategory(); // 第二步:读取这口有产量干扰井上次确认的包含状态。 oWellRow.m_bCanCalculate = true; oWellRow.m_bIsIncluded = m_pDataManager != nullptr && m_pDataManager->getNumericalAnalysisCase()->isIncludedWell( oWellRow.m_sWellCode); // 第三步:井别唯一决定产量列;不再把所有井都显示为油量。 oWellRow.m_sPressure = bHasValidPressure ? tr("History") : tr("None"); oWellRow.m_sOilProd = tr("None"); oWellRow.m_sGasProd = tr("None"); oWellRow.m_sWaterProd = tr("None"); if(oWellRow.m_eWellCategory == NM_WellCategory_Oil) { oWellRow.m_sOilProd = tr("Rate"); } else if(oWellRow.m_eWellCategory == NM_WellCategory_Gas) { oWellRow.m_sGasProd = tr("Rate"); } else if(oWellRow.m_eWellCategory == NM_WellCategory_Water) { oWellRow.m_sWaterProd = tr("Rate"); } oWellRow.m_eMode = NM_CaseWell_RateControlled; // 添加到数据列表和表格 m_vecWellData.append(oWellRow); addWellDataToTable(oWellRow, nDisplayRow); ++nDisplayRow; } m_pTableWidget->setRowCount(nDisplayRow); // 调整实际显示的行数 m_pTableWidget->horizontalHeader()->setStretchLastSection(true); m_pTableWidget->horizontalHeader()->setResizeMode(QHeaderView::Stretch); } void nmWxIncludeOtherWells::addWellDataToTable(const WellDataRow& data, int row) { // Name列 - 不可编辑 QTableWidgetItem* nameItem = new QTableWidgetItem(data.m_sName); nameItem->setFlags(nameItem->flags() & ~Qt::ItemIsEditable); nameItem->setData(Qt::UserRole, data.m_sWellCode); // 表格内部始终携带 WellCode nameItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter); m_pTableWidget->setItem(row, 0, nameItem); // Included列 - 使用自定义复选框组件 QWidget* pWidget = new QWidget(); QCheckBox* pCheckBox = new QCheckBox(); QHBoxLayout* pLayout = new QHBoxLayout(pWidget); pLayout->addWidget(pCheckBox); pLayout->setAlignment(Qt::AlignCenter); pLayout->setContentsMargins(0, 0, 0, 0); pWidget->setLayout(pLayout); pCheckBox->setChecked(data.m_bIsIncluded); // 表内只有其他有产量井,用户可以决定它是否作为干扰井参与计算。 pCheckBox->setEnabled(data.canCalculate()); pCheckBox->setProperty("row", row); // 存储行索引 // 连接复选框信号 connect(pCheckBox, SIGNAL(stateChanged(int)), this, SLOT(onCheckBoxStateChanged(int))); // 设置单元格控件 m_pTableWidget->setCellWidget(row, 1, pWidget); // 其他列只显示各类 simulation target,与 Saphir 对话框保持一致。 QStringList listOtherData; listOtherData.append(data.m_sOilProd); listOtherData.append(data.m_sGasProd); listOtherData.append(data.m_sWaterProd); listOtherData.append(data.m_sPressure); for(int col = 2; col < 6; col++) { QTableWidgetItem* item = new QTableWidgetItem(listOtherData[col-2]); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, row); item->setTextAlignment(Qt::AlignCenter); m_pTableWidget->setItem(row, col, item); } } void nmWxIncludeOtherWells::onCheckBoxStateChanged(int state) { QCheckBox* pCheckBox = qobject_cast(sender()); if(pCheckBox == nullptr) { return; } const int nRow = pCheckBox->property("row").toInt(); if(nRow < 0 || nRow >= m_vecWellData.size()) { return; } // 主井正常不会进入本表;保留该判断作为防御,避免未来改动误取消主井。 if(m_vecWellData[nRow].m_bIsPrimary) { m_vecWellData[nRow].m_bIsIncluded = true; return; } // 其他候选井只记录选择状态,绝不在该对话框内创建或删除 Map 井。 m_vecWellData[nRow].m_bIsIncluded = (state == Qt::Checked); m_pTableWidget->selectRow(nRow); } void nmWxIncludeOtherWells::onItemClicked(QTableWidgetItem* item) { } QVector nmWxIncludeOtherWells::getWellData() const { return m_vecWellData; } void nmWxIncludeOtherWells::setupButtons() { // 创建确定和取消按钮 m_pOkButton = new QPushButton(tr("OK"), this); m_pCancelButton = new QPushButton(tr("Cancel"), this); } void nmWxIncludeOtherWells::setupLayouts() { // 创建按钮布局并添加按钮 m_pButtonLayout = new QHBoxLayout(); m_pButtonLayout->addStretch(); // 添加伸缩项使按钮靠右 m_pButtonLayout->addWidget(m_pOkButton); m_pButtonLayout->addWidget(m_pCancelButton); // 创建主布局并添加控件 m_pMainLayout = new QVBoxLayout(this); m_pMainLayout->addWidget(m_pTableWidget); m_pMainLayout->addLayout(m_pButtonLayout); setLayout(m_pMainLayout); } void nmWxIncludeOtherWells::setupConnections() { connect(m_pOkButton, SIGNAL(clicked()), this, SLOT(accept())); connect(m_pCancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(m_pTableWidget, SIGNAL(itemClicked(QTableWidgetItem*)), this, SLOT(onItemClicked(QTableWidgetItem*))); }