#include "zxLogInstance.h" #include "ZxBaHelper.h" #include #include "ZxResolutionHelper.h" #include "zxSysUtils.h" #include "ZxPtyDock.h" #include "iDockBaseWx.h" #include "ZxMainWindow.h" #include "ZxTabWidget.h" #include "ZxSubAxisX.h" #include "ZxSubAxisY.h" #include "ZxPlot.h" #include "ZxObjCurve.h" #include "ZxSubTitle.h" #include "tCurvePlotScene.h" #include "tCurvePlotView.h" #include "ZxTableView.h" #include "ZxTableModel.h" #include "mModuleDefines.h" #include "ZxDataWell.h" #include "ZxDataProject.h" #include "ZxRstJobWnd.h" #ifdef QT_DEBUG #include "ZxDataGaugeP.h" #endif #ifdef QT_DEBUG #include "nmXmlHelper.h" #endif #include "nmGuiPlot.h" #include "nmSubWndMain.h" #include "nmPlotDialogContext.h" #include "nmPlotDialogContextProvider.h" #include "nmWxGridVTKContainerWidget.h" #include "nmWxSelectWellsDlg.h" #include "nmWxSelectWellsWidget.h" #include "nmWxParameterProperty.h" #include "nmCalculationDllPebiSolverTask.h" #include "nmCalculationUtils.h" #include "nmObjPointWell.h" #include "nmDataAnalyzeManager.h" #include "nmDataDemo.h" #include "nmDataLogFile.h" #include "nmDataMeasure.h" #include "nmWxParaProperty.h" #include "nmWxRCDialog.h" #include "nmWxWellLayerDlg.h" #include "nmWxGeometryLayerDlg.h" #include "nmWxReservoirPropertiesDlg.h" #include "nmWxPostprocessingAnimationWidget.h" #include "nmWxGeoRefDlg.h" #include "iSubWndFitting.h" #include #include "nmSingalCenter.h" #include "nmWxSelectResultWellsWidget.h" #include "nmWxResultParameters.h" #include "nmWxReservoirProperties.h" #include "nmCalculationPebiGrid.h" #include "nmDataOutline.h" #include "nmDataVerticalFracturedWell.h" #include "nmDataHorizontalFracturedWell.h" #include "nmDataVerticalWell.h" #include "ZxDataGaugeP.h" #include "ZxDataGaugeF.h" #include "nmWxDFN.h" #include "nmWxDisplaySettings.h" #include "nmDataMixedResults.h" #include "ZxRstWnd.h" #include namespace { // 保留原来求解器单例的防重入语义:全局同一时间只允许一个DLL求解任务运行。 // QPointer会在QObject销毁后自动变空,避免保留已经释放的线程指针。 QPointer s_pRunningSolverTask; } nmSubWndMain::nmSubWndMain(QWidget *parent, QString sExt) : iSubWndBaseFit(parent, sExt) { m_pWxPlot = NULL; m_pWxDockParas = NULL; m_pWxParas = NULL; m_pWxDockData1 = NULL; m_pTableView1 = NULL; m_pWxDockData2 = NULL; m_pTableView2 = NULL; #ifdef QT_DEBUG m_pWxDockTemp = NULL; m_pListWxTemp = NULL; #endif // 为了后续支持多井提供方便 if(m_pDataWell == NULL) { m_pDataWell = zxCurWell; } //m_sMdiWndType = s_MdiType_DataNum; m_sMdiWndType = s_MdiType_DataAnal; setWindowTitle(tr("nmSubWndMain")); m_lockState = false; // 默认为false m_resultDataDlg = nullptr; m_openDialogCmdIds.clear(); m_pProgressDlg = nullptr; m_pSolverTask = nullptr; m_pFakeProgressTimer = nullptr; m_nVirtualProgress = 0; m_nSlowDownCounter = 0; m_pPlotToolBar = nullptr; } nmSubWndMain::~nmSubWndMain() { #ifdef QT_DEBUG // 坚持谁创建谁析构原则,删除(首先需要去除绑定) if(NULL != m_pWxDockTemp) { //QObject* pParent = m_pWxDockTemp->parent(); //ZxMainWindow* p = dynamic_cast(pParent); ZxMainWindow* p = m_pMainWindow; if(NULL != p) { p->detachOuterDockWx(m_pWxDockTemp); } delete m_pWxDockTemp; m_pWxDockTemp = NULL; } #endif this->setTopDocksVisible(true); // TODO:删除已有在图元的数据对象 //if (m_pWxPlot != nullptr) { // QVector vecObjs = m_pWxPlot->getAllPlots(); // foreach(nmObjBase* obj, vecObjs) { // obj->removeData(); // } //} if(m_resultDataDlg != nullptr) { delete m_resultDataDlg; m_resultDataDlg = nullptr; } if (m_pFakeProgressTimer) { m_pFakeProgressTimer->stop(); // 因为构造时传了 this,这里不 delete 也可以,但 disconnect 是安全的 m_pFakeProgressTimer->disconnect(); } if (m_pProgressDlg) { delete m_pProgressDlg; m_pProgressDlg = NULL; } if (m_pSolverTask) { // 窗口销毁时只解除本窗口的回调;若线程仍在运行,让线程自己结束后释放。 disconnect(m_pSolverTask, SIGNAL(sig_calculateDone(bool)), this, SLOT(on_solverTaskFinished(bool))); if (m_pSolverTask == s_pRunningSolverTask && !m_pSolverTask->isRunning()) { s_pRunningSolverTask = nullptr; } if (!m_pSolverTask->isRunning()) { m_pSolverTask->deleteLater(); } m_pSolverTask = nullptr; } /*if (m_parameterPropertyWindow != nullptr) { delete m_parameterPropertyWindow; m_parameterPropertyWindow = nullptr; }*/ } void nmSubWndMain::configWnd(QString sPrevInfo) { iSubWndBaseFit::configWnd(sPrevInfo); if(NULL != m_pMainWindow) { disconnect(this, SIGNAL(sigAppendDock2Main(iDockBaseWx*, Qt::DockWidgetArea)), \ m_pMainWindow, SLOT(slotAppendDock2Main(iDockBaseWx*, Qt::DockWidgetArea))); connect(this, SIGNAL(sigAppendDock2Main(iDockBaseWx*, Qt::DockWidgetArea)), \ m_pMainWindow, SLOT(slotAppendDock2Main(iDockBaseWx*, Qt::DockWidgetArea))); } initUI(); } void nmSubWndMain::initUI() { // iSubWndBaseAF::initUI(); #ifdef QT_DEBUG // 示例:演示增加Dock并且追加至程序主窗口 initUiTop(); #endif // 主布局:定义 initUiMain(); // 外围布局,DockWx { initUiDockWxs(); initUiDockPtys(); } #ifdef QT_DEBUG // 示例:如何加载xml文件 if(_nmXmlHelper->loadXmlDefines()) { foreach(nmXmlData* pData, *(_nmXmlHelper->getVecNmXmlDataPtrs())) { Q_ASSERT(NULL != pData); qDebug() << QString("%1: %2").arg(pData->m_sName).arg(pData->m_sAlias); } } #endif } QWidget* nmSubWndMain::initUiMainWx() { QSplitter* pSplitter = new QSplitter(Qt::Vertical); Q_ASSERT(NULL != pSplitter); nmGuiPlot* pWxPlot = new nmGuiPlot(); m_pWxPlot = pWxPlot; // 将绘图对象添加到数据中心 nmDataAnalyzeManager::getCurrentInstance()->setPlot(m_pWxPlot); { // 建立信号,以便在此处增加新的工具 connect(pWxPlot, SIGNAL(sigToolbarBuilt(QToolBar*)), this, SLOT(slotToolbarBuilt(QToolBar*))); QSize sz = QSize(265, 203); pWxPlot->initUI("TestGui", sz); bindChartSignals(pWxPlot); pSplitter->addWidget(pWxPlot); } return pSplitter; } void nmSubWndMain::initUiDockWxs() { // TODO,本Dock的操作 // 基础参数Dock // { // m_pWxDockParas = new iDockBaseWx(tr("Parameters")); // Q_ASSERT (NULL != m_pWxDockParas); // addDockWidget(Qt::LeftDockWidgetArea, m_pWxDockParas); // m_pWxParas = new nmWxParaProperty(); // Q_ASSERT (NULL != m_pWxParas); // m_pWxParas->initUI(); // m_pWxDockParas->setWidget(m_pWxParas); // m_pWxDockParas->setMinimumWidth(_resoSizeW(200)); // } // 表格数据Dock // { // QStringList listTitles; // listTitles << tr("Name1"); // iDockBaseWx* pDockWx1 = new iDockBaseWx(tr("Data1")); // Q_ASSERT (NULL != pDockWx1); // { // addDockWidget(Qt::RightDockWidgetArea, pDockWx1); // m_pWxDockData1 = pDockWx1; // ZxTableView* pTableView = new ZxTableView(); // Q_ASSERT (NULL != pTableView); // { // ZxTableModel* pTableModel = new ZxTableModel(1, 1, listTitles); // Q_ASSERT (NULL != pTableModel); // pTableView->setModel(pTableModel); // pTableView->setMenuMode(ZxTableView::MTM_Edit_Without_Col); // pTableView->setSelectionBehavior(ZxTableView::SelectRows); // pTableView->fuzzyUiOfQt5(); // } // pDockWx1->setWidget(pTableView); // m_pTableView1 = pTableView; // } // iDockBaseWx* pDockWx2 = new iDockBaseWx(tr("Data2")); // Q_ASSERT (NULL != pDockWx2); // { // addDockWidget(Qt::RightDockWidgetArea, pDockWx2); // tabifyDockWidget(pDockWx1, pDockWx2); // m_pWxDockData2 = pDockWx2; // ZxTableView* pTableView = new ZxTableView(); // Q_ASSERT (NULL != pTableView); // { // ZxTableModel* pTableModel = new ZxTableModel(1, 1, listTitles); // Q_ASSERT (NULL != pTableModel); // pTableView->setModel(pTableModel); // pTableView->setMenuMode(ZxTableView::MTM_Readonly); // pTableView->fuzzyUiOfQt5(); // } // pDockWx2->setWidget(pTableView); // m_pTableView2 = pTableView; // } // } } void nmSubWndMain::initUiDockPtys() { iSubWndBaseAF::initUiDockPtys(); // 属性Dock { Q_ASSERT(NULL != m_pDockPty); m_pDockPty->setMinimumWidth(_resoSizeW(200)); } } #ifdef QT_DEBUG // 示例:演示增加Dock并且追加至程序主窗口 void nmSubWndMain::initUiTop() { #if 0 return; // 隐藏所有Dock this->setTopDocksVisible(false); // 创建新的Dock iDockBaseWx* pDockWx = new iDockBaseWx(tr("TODO:Demo")); Q_ASSERT(NULL != pDockWx); // QListWidget* pListWx = new QListWidget(); nmWxTreeWidget* treeWidget = new nmWxTreeWidget(pDockWx, m_pAnalyzeData); Q_ASSERT(NULL != treeWidget); pDockWx->setWidget(treeWidget); // m_pListWxTemp = pListWx; pDockWx->setMinimumWidth(_resoSizeW(200)); emit sigAppendDock2Main(pDockWx, Qt::LeftDockWidgetArea); m_pWxDockTemp = pDockWx; return; // 基础参数Dock // { // iDockBaseWx* pDockWx = new iDockBaseWx(tr("TODO:Demo")); // Q_ASSERT (NULL != pDockWx); // QListWidget* pListWx = new QListWidget(); // Q_ASSERT (NULL != pListWx); // pDockWx->setWidget(pListWx); // m_pListWxTemp = pListWx; // pDockWx->setMinimumWidth(_resoSizeW(200)); // emit sigAppendDock2Main(pDockWx, Qt::LeftDockWidgetArea); // m_pWxDockTemp = pDockWx; // } #endif } #endif void nmSubWndMain::bindChartSignals(iGuiPlot* pWxPlot) { nmGuiPlot* p = dynamic_cast(pWxPlot); if(NULL != p) { connect(p, SIGNAL(sigObjSelChanged(ZxObjBase*, bool)), \ this, SLOT(slotObjSelChanged(ZxObjBase*, bool))); connect(p, SIGNAL(sigObjPtsChanged(ZxObjBase*)), this, SLOT(slotObjPtsChanged(ZxObjBase*))); } iSubWndBaseAF::bindChartSignals(pWxPlot); } bool nmSubWndMain::runActionOf(QString sAction) { if(iSubWnd::runActionOf(sAction)) { return true; } // 数据加载 QString s = sAction; if(_isSame(s, "LoadP")) { return true; } return false; } bool nmSubWndMain::runCmdBy(QString sName, QString sID) { QString s = sName; int nId = sID.toInt(); // 运行菜单之前,先将所有处于选中状态的图元状态恢复 if(m_pWxPlot != nullptr) { m_pWxPlot->clearPlotsSelectStates(); } switch(nId) { case 5102: this->geologicalMapImport(); return true; /*case 5103: this->geologicalMapHide(); return true;*/ case 5120: this->drawMeasuringScale(); return true; case 5103: this->drawPolygonOutline(); return true; case 5104: this->drawSquareOutline(); return true; case 5105: this->drawRoundOutline(); return true; case 5106: this->drawFault(); return true; case 5107: this->selectWell(); return true; case 5108: this->drawWell(); return true; case 5109: this->drawCrack(); return true; case 5110: this->drawRegion(); return true; case 5111: this->drawRegionMark(); return true; case 5112: this->geoLayering(); return true; case 5113: this->reservoirCharacteristics(); return true; /*case 5114: this->generationMesh(); return true; */ case 5115: this->solveAndAnalyze(); return true; case 5117: this->mergeAnaResultToFitting(); return true; case 5121: this->deleteOneObj(); return true; case 5119: this->setLocked(); return true; case 5122: this->generateDFN(); return true; case 5123: this->displaySetting(); return true; /* case 5117: this->initData(); return true; */ case 5129: if(isDialogCmdOpened(5129)) { return true; } this->drawMeasure(); return true; case 5127: this->drawGeoRef(); return true; case 5128: if(isDialogCmdOpened(5128)) { return true; } this->drawPointerPos(); return true; } if(_isSame(s, "RunGrid")) { if(NULL != m_pWxPlot) { //m_pWxPlot->refreshGrid(true); } return true; } return false; } bool nmSubWndMain::checkCmdEnable(bool &b, \ QString sName, int nID, \ bool bLicensed) { bool b1 = (NULL != zxCurProject); bool b2 = (NULL != m_pDataWell); // 判断当前锁定状态 if(m_lockState) { /* if(nID >= 5102 && nID <= 5125) { b = (b1 && b2 && bLicensed && !isReadonly() && NULL != m_pWxPlot); return true; } */ /* if ((nID >= 5122 && nID <= 5125) || (nID >= 5112 && nID <= 5119 )) { b = true; return true; } */ /* if(nID >= 5102 && nID <= 5124) { b = true; return true; } */ // 可使用菜单栏 if(sName == "NmMap" || sName == "NmUnlocked" || sName == "NmGeometry" || sName == "NmProperties" || sName == "NmDFN" || sName == "NmCaculation" || sName == "NmBack" || sName == "NmResult" || sName == "NmGrid" || sName == "NmShow" || sName == "NmPrintPreview" || sName == "NmPrint" || sName == "VisibleAnalBasic" || sName == "VisibleAnalPVT" || sName == "VisibleAnalDiff" || sName == "VisibleAnalPseu" || sName == "nmFitModel" || sName == "NmAnalChange") { b = true; return true; } else { b = false; return false; } } else { if((nID >= 5102 && nID <= 5130) /*|| (nID >= 9002 && nID <= 9003) */ || (nID >= 9101 && nID <= 9104) || nID == 3104) { b = (b1 && b2 && bLicensed && !isReadonly() && NULL != m_pWxPlot); return true; } } return iSubWndBaseFit::checkCmdEnable(b, sName, nID, bLicensed); } void nmSubWndMain::reAdjustToolbar(QToolBar* pToolBar) { iSubWndBaseAF::reAdjustToolbar(pToolBar); m_pPlotToolBar = pToolBar; // 获取所有动作的列表 // QList actions = m_pPlotToolBar->actions(); // // 隐藏第1个和第2个动作 // if (actions.size() > 0) { // actions[0]->setVisible(false); // 隐藏第1个动作 // } // if (actions.size() > 1) { // actions[1]->setVisible(false); // 隐藏第2个动作 // } } void nmSubWndMain::firstLoadAndUpdate() { iSubWndBaseAF::firstLoadAndUpdate(); } void nmSubWndMain::finalDeals() { iSubWndBaseAF::finalDeals(); #ifdef QT_DEBUG updatePlots(); updateDockWxs(); if(m_pWxDockData1 != NULL) { Q_ASSERT(NULL != m_pWxDockData1); m_pWxDockData1->raise(); } #endif } void nmSubWndMain::onActivated() { #ifdef QT_DEBUG // 当前窗体激活时,可以做些事情,比如把隐藏的Dock显示出来 if(NULL != m_pWxDockTemp) { if(!m_pWxDockTemp->isVisible()) { m_pWxDockTemp->setVisible(true); } } #endif } #ifdef QT_DEBUG void nmSubWndMain::updatePlots() { #if 0 // 里面根据曲线,重新刷了一下坐标轴范围。你屏蔽该函数,即可 // 坐标轴范围会变成背景图的大小 return ; // 说明:以从当前井获取一条压力数据进行绘图为例 QString sType = iDataModelType::sTypeDataGaugeP; QString sCodeP = ""; //如果已知压力数据Code,可以直接引用 ZxDataGaugeP* pDataObjP = dynamic_cast(getDataObjOf(sType, sCodeP)); if(NULL == pDataObjP) { qDebug() << tr("Failed to get data of type '%1'").arg(sType); return; } VecDouble vecX, vecY; QByteArray ba = pDataObjP->getGaugeDataOf(0); if(!ZxBaHelper::convertBa2VecXY(vecX, vecY, ba)) { qDebug() << tr("Failed to get x-y data of dataobj '%1'").arg(pDataObjP->getCode()); return; } nmGuiPlot* pWxPlot = m_pWxPlot; Q_ASSERT(NULL != pWxPlot); QString sName = tr("CurveName"); ZxObjBase* pObj = pWxPlot->updatePlotObjBy(sName, vecX, vecY, true); if(NULL != pObj) { pObj->setLockPos(true); //可以调整属性 // pObj->setReadOnly(true); pWxPlot->freshAxisScales(true);//刷新坐标轴刻度 // 设置标题+坐标轴等 pWxPlot->setAxisX(tr("Time"), "hr"); pWxPlot->setAxisY(tr("Pressure"), "MPa"); pWxPlot->setAxisXYLog(false, 0); pWxPlot->setAxisXYLog(false, 1); pWxPlot->m_pPlot->setLegendVisible(false); pWxPlot->m_pPlot->getTitle()->setName(tr("Demo")); } #endif } ZxDataObject* nmSubWndMain::getDataObjOf(QString sType, QString sCode /*= ""*/) { ZxDataWell* pDataWell = zxCurWell; Q_ASSERT(NULL != pDataWell); ZxDataObject* pDataObj = NULL; if(!sCode.isEmpty()) { pDataObj = pDataWell->getChild(sType, sCode); } else { ZxDataObjectList vecObjs = pDataWell->getChildren(sType); if(!vecObjs.isEmpty()) { pDataObj = vecObjs[0]; } } return pDataObj; } void nmSubWndMain::updateDockWxs() { #if 0 // TODO,刷新Dock内容 return; // 左侧参数窗体 Q_ASSERT(NULL != m_pWxParas); QStringList listParas; listParas << "K" << "S" << "rw" << "Miuo" << "Bo" << "phi"; m_pWxParas->refreshUIs(listParas); // 表格数据1 Q_ASSERT(NULL != m_pTableView1); ZxTableModel* pTableModel = m_pTableView1->getModel(); Q_ASSERT(NULL != pTableModel); QStringList listTitles; listTitles << tr("Col1") << tr("Col2\n(MPa)"); VVecDouble vvec; { VecDouble vec; vec << 0.2 << 3.4; vvec << vec; } { VecDouble vec; vec << 5.6 << 0.456; vvec << vec; } pTableModel->setTitles(listTitles); pTableModel->setData(vvec); if(NULL != m_pListWxTemp) { m_pListWxTemp->clear(); for(int i = 0; i < 10; i++) { QString sItem = tr("Demo Item %1").arg(i + 1); QListWidgetItem* pItem = new QListWidgetItem(sItem); Q_ASSERT(NULL != pItem); pItem->setIcon(zxLoadIcon("Open")); m_pListWxTemp->addItem(pItem); } } #endif } void nmSubWndMain::updateTableByCurve(ZxObjCurve* pObjCurve, ZxTableView* pTableView) { Q_ASSERT(NULL != pObjCurve); Q_ASSERT(NULL != pTableView); // 刷新表格标题 { QString sNameX = pObjCurve->getAxisX()->getName(); QString sUnit = pObjCurve->getAxisX()->getUnit(); if(!sUnit.isEmpty()) { sNameX += QString("\n(%1)").arg(sUnit); } QString sNameY = pObjCurve->getAxisY()->getName(); sUnit = pObjCurve->getAxisY()->getUnit(); if(!sUnit.isEmpty()) { sNameY += QString("\n(%1)").arg(sUnit); } QStringList listTitles; listTitles << sNameX << sNameY; pTableView->getModel()->setTitles(listTitles); } // 刷新表格数据 { VVecDouble vvec; QVector vecValues = pObjCurve->getAllValues(); for(int i = 0; i < vecValues.count(); i++) { VecDouble vec; vec << vecValues.at(i).x() * 1.0; vec << vecValues.at(i).y() * 1.0; vvec << vec; } pTableView->getModel()->setData(vvec); } } #endif void nmSubWndMain::slotObjSelChanged(ZxObjBase* p, bool b) { #ifdef QT_DEBUG // 如果选中了一条曲线,则把其数据显示在数据表格2中 ZxObjCurve* pObjCurve = dynamic_cast(p); if(NULL != pObjCurve && b) { Q_ASSERT(NULL != m_pWxDockData2); m_pWxDockData2->raise(); updateTableByCurve(pObjCurve, m_pTableView2); } #endif } void nmSubWndMain::slotObjPtsChanged(ZxObjBase* p) { } void nmSubWndMain::onSerialize(ZxSerializer* ser) { iSubWndBaseAF::onSerialize(ser); if(NULL != m_pWxPlot) { m_pWxPlot->setModified(false); } } void nmSubWndMain::onDeserialize(ZxSerializer* ser) { iSubWndBaseAF::onDeserialize(ser); if(NULL != m_pWxPlot) { m_pWxPlot->setModified(false); } } void nmSubWndMain::onDeserialized() { if(NULL != m_pWxPlot) { m_pWxPlot->resetAfterDeserialized(); } } //bool nmSubWndMain::loadRss() { // ZxRstJobWnd* pRstWnd = getRstJobWnd(); // Q_ASSERT(NULL != pRstWnd); // // 基础信息 // { // QByteArray v = pRstWnd->getDataInfo(); // IxSerDes* pSerObj = this; // if(!loadRstInfoFromArr(v, pSerObj)) { // return false; // } // } // // 图形 // if(NULL != m_pWxPlot) { // QByteArray v = pRstWnd->getDataInfo1(); // ZxPlot* pPlot = NULL; // loadOnePlot(pPlot, v); // if(NULL != pPlot) { // m_pWxPlot->m_pPlotScene->freshToPlot(pPlot, // m_pWxPlot->m_pPlotView); // m_pWxPlot->m_pPlot = m_pWxPlot->m_pPlotScene->m_pPlot; // pPlot->resetTools(m_pWxPlot->m_pPlotView); // m_pWxPlot->resetAfterDeserialized(); // } // m_pWxPlot->runUpdate(); // } // return true; //} //bool nmSubWndMain::saveRss() { // ZxRstJobWnd* pRstWnd = getRstJobWnd(); // if(NULL == pRstWnd) { // return false; // } // // 基础信息 // { // QByteArray v; // IxSerDes* pSerObj = this; // if(!saveRstInfoToArr(v, pSerObj)) { // return false; // } // pRstWnd->setDataInfo(v); // } // // 图形 // if(NULL != m_pWxPlot) { // ZxPlot* pPlot = m_pWxPlot->m_pPlot; // { // QByteArray v1; // if(saveOnePlot(pPlot, v1)) { // pRstWnd->setDataInfo1(v1); // } // } // } // return pRstWnd->save(); //} bool nmSubWndMain::loadRsts() { return true;// /* ZxRstWnd* pRstWnd = getRstUtilWnd(); Q_ASSERT (nullptr != pRstWnd); // 基础信息 if (!loadRstBase(pRstWnd)) { return false; } // 图形 if (nullptr != m_pWxPlot) { QByteArray v = QByteArray(); pRstWnd->loadSubPlotContent(v); ZxPlot* pPlot = nullptr; loadOnePlotFromBa(pPlot, v); if (nullptr != pPlot) { m_pWxPlot->m_pPlotScene->freshToPlot(pPlot, m_pWxPlot->m_pPlotView); m_pWxPlot->m_pPlot = m_pWxPlot->m_pPlotScene->m_pPlot; pPlot->resetTools(m_pWxPlot->m_pPlotView); m_pWxPlot->resetAfterDeserialized(); } m_pWxPlot->runUpdate(); }//*/ } bool nmSubWndMain::saveRsts() { ZxRstWnd* pRstWnd = this->getRstUtilWnd(); if(nullptr == pRstWnd) { return false; } return pRstWnd->save(); // // 基础信息 // if (!saveRstBase(pRstWnd)) // { // return false; // } // // 图形 // if (nullptr != m_pWxPlot) // { // ZxPlot* pPlot = m_pWxPlot->m_pPlot; // { // QByteArray v1; // if (saveOnePlotToBa(pPlot, v1)) // { // pRstWnd->saveSubPlotContent(v1); // } // } // } //return pRstWnd->save(); } bool nmSubWndMain::slotSaveAll() { ZxRstWnd* pRstWnd = getRstUtilWnd(); Q_ASSERT(NULL != pRstWnd); if(pRstWnd == NULL) { return false; } return saveRsts(); } void nmSubWndMain::updateSelectedWells(QList wellObjList) { // if(wellObjList.count() == 0) { // return; // } // setp 1,获取现在画布上所有井的 ZxDataWell* 数据指针 QVector pWellPlotList = m_pWxPlot->getWellPlots(); // QMap 用于快速查找和构建当前画布上的井数据列表 QMap pWellDataToPlotMap; for(int i = 0; i < pWellPlotList.count(); ++i) { nmObjPointWell* wellPlot = pWellPlotList[i]; ZxDataWell *pWellData = wellPlot->getWellData(); if (pWellData) { // 确保数据不为空 pWellDataToPlotMap.insert(pWellData, wellPlot); } } // 当前在画布上的所有 ZxDataWell* 数据列表 (Key Set) QList pWellPlotDataList = pWellDataToPlotMap.keys(); // setp 2,找出需要 REMOVE (删除) 的图元 QVector vDeleteWellPlotList; // 遍历所有当前在画布上的井数据 for(int i = 0; i < pWellPlotDataList.count(); ++i) { ZxDataWell *pWellDataOnPlot = pWellPlotDataList[i]; // 如果该井数据不在用户选中的列表 wellObjList 中,则需要删除 if (!wellObjList.contains(pWellDataOnPlot)) { // 从 Map 中获取对应的图元对象 vDeleteWellPlotList.append(pWellDataToPlotMap.value(pWellDataOnPlot)); } } // setp 3,找出需要 ADD (添加) 的井数据 QVector vAddWellPlotList; // 遍历所有用户选中的井数据 wellObjList for(int i = 0; i < wellObjList.count(); ++i) { ZxDataWell *pWellDataSelected = wellObjList[i]; // 确保井数据有效 if (pWellDataSelected && !pWellPlotDataList.contains(pWellDataSelected)) { // 如果该井数据不在当前画布上的数据列表中,则需要添加 vAddWellPlotList.append(pWellDataSelected); } } // setp 4,执行删除操作 for(int i = 0; i < vDeleteWellPlotList.count(); ++i) { nmObjPointWell* pWellPlot = vDeleteWellPlotList[i]; // 如果是当前井,不可删除 (保留您的逻辑) if(pWellPlot->getNmWellData() == nmDataAnalyzeManager::getCurrentInstance()->getCurWellData()) continue; // 删除对应的参数类 pWellPlot->removeData(); // 实际从画布上删除图元 m_pWxPlot->m_pPlot->removeObjByName(pWellPlot->getName()); } // setp 5,将vAddWellPlotList中的井数据,构建图元,添加到画布上 for(int i = 0; i < vAddWellPlotList.count(); i++) { ZxDataWell* wellObj = vAddWellPlotList[i]; QString sName = wellObj->getName(); QVector points; points.append(QPointF(wellObj->getLocationX(), wellObj->getLocationY())); // 构建了图元 nmObjPointWell* pWellPlot = NULL; pWellPlot = (nmObjPointWell*)m_pWxPlot->appendOneObj(NMOT_Point_Well, sName, points); if(pWellPlot == NULL) { continue; } // 设置图元的井数据 pWellPlot->setWellData(wellObj); // 移动到正确的位置 pWellPlot->moveToPos(pWellPlot->getPosOf(pWellPlot->getAllPos())); pWellPlot->afterCreated(); //选择完后初始化参数 } // 添加完毕后,重新渲染 m_pWxPlot->update(); } // 地质图导入 void nmSubWndMain::geologicalMapImport() { //打开图片选择弹框 //打开文件对话框选择图片文件 //QString filePath = QFileDialog::getOpenFileName(nullptr, "选择图片文件", "", "Images (*.png *.xpm *.jpg)"); //if(!filePath.isEmpty()) { // // 画布 设置背景,并自适应宽高 // ZxPlot* pPlot = m_pWxPlot->m_pPlot; // pPlot->setBkImgFile(filePath); // // QImage* pBkImg = pPlot->getBkImg(); // // Q_ASSERT (NULL != pBkImg); // // int w = pBkImg->width(); // // int h = pBkImg->height(); // // pPlot->getMainAxisX()->setRangeMinMax(0, w, true); // // pPlot->getMainAxisY()->setRangeMinMax(0, h, true); // nmDataLogFile::getInstance()->writeLog(filePath); //} QString sFilter = "PNG Images (*.png);;" "JPEG Images (*.jpg *.jpeg);;" "Bitmap Images (*.bmp);;" "All Files (*)"; QString sFile = QFileDialog::getOpenFileName( nullptr, tr("Open File"), ZxBaseUtil::getLastDir(), sFilter ); if(sFile.isEmpty() || !QFile::exists(sFile)) { return; } // 更新最后访问目录 QFileInfo fi(sFile); ZxBaseUtil::setLastDir(fi.absolutePath()); // 输出文件失败原因 QImageReader reader(sFile); if(!reader.canRead()) { // 输出具体错误 qDebug() << "Error Message: " << reader.errorString(); return; } if(m_pWxPlot == nullptr || m_pWxPlot->m_pPlot == nullptr) { return; } // 设置背景图片 ZxPlot* pPlot = m_pWxPlot->m_pPlot; pPlot->setBkImgFile(sFile); // 检查 ZxPlot 是否成功加载图片 QImage* pBkImg = pPlot->getBkImg(); Q_ASSERT(nullptr != pBkImg); if(pBkImg == nullptr) { return; } // 将图片信息存储到数据中心 nmDataAnalyzeManager* pManager = nmDataAnalyzeManager::getCurrentInstance(); if(pManager) { QImage loadedImage = reader.read(); // 假设已经读取成功 BackgroundImageInfo bgInfo; bgInfo.bIsVisible = true; // 默认设置为可见 bgInfo.sFilePath = sFile; // 当前背景文件路径 bgInfo.objImage = loadedImage; // 存储QImage对象 pManager->setBackgroundImageInfo(bgInfo); // 设置背景图片信息 } // 手动调整坐标轴(如果 ZxPlot 未自动调整) //int w = pBkImg->width(); //int h = pBkImg->height(); //if (w > 0 && h > 0) { // pPlot->getMainAxisX()->setRangeMinMax(0, w, true); // pPlot->getMainAxisY()->setRangeMinMax(0, h, true); //} } void nmSubWndMain::drawMeasuringScale() { this->triggerToolBarAction(NMOT_Line_MeasuringScale); } void nmSubWndMain::geologicalMapHide() { } void nmSubWndMain::setTopDocksVisible(bool visible) { // 获取主程序所有 Dock 视图 QList dockWidgets = m_pMainWindow->findChildren(); // 遍历所有 Dock 视图并移除位于左侧的 foreach(QDockWidget* dock, dockWidgets) { if(visible) { dock->show(); } else { dock->hide(); } } } void nmSubWndMain::drawPolygonOutline() { // 获取多边形边界的绘制,并模拟触发点击操作 // 目前多边形边界绘制是工具栏的第4个,所以用 3 // QList actions = m_pPlotToolBar->actions(); // if (!actions.isEmpty()) { // QAction *action = actions[3]; // action->trigger(); // } this->triggerToolBarAction(NMOT_PolygonOutline); } void nmSubWndMain::drawSquareOutline() { // 获取矩形边界的绘制,并模拟触发点击操作 this->triggerToolBarAction(NMOT_RectOutline); } void nmSubWndMain::drawRoundOutline() { // 获取矩形边界的绘制,并模拟触发点击操作 this->triggerToolBarAction(NMOT_RoundOutline); } void nmSubWndMain::drawFault() { this->triggerToolBarAction(NMOT_Line_Fault); } void nmSubWndMain::selectWell() { if(m_pWxPlot == nullptr || zxCurProject == nullptr) { return; } // 先获取已经添加到的界面中井 QStringList wellPlotNameList = m_pWxPlot->getWellNames(); // 先找到所有的井 int wellCount = zxCurProject->getChildrenCount(iDataModelType::sTypeWell); ZxDataObjectList wellList = zxCurProject->getChildren(iDataModelType::sTypeWell); nmDataLogFile::getInstance()->writeLog(QString(" %1 %2").arg(wellCount).arg(wellList.size())); // 井的名字 QStringList listWellNames; // 井的code QList wellCodes; // 井的名字到井数据指针的Map QMap wellNameToObjMap; // 数据整理 for(int i = 0; i < wellList.size(); i++) { ZxDataWell* wellObj = (ZxDataWell*)wellList[i]; nmDataLogFile::getInstance()->writeLog(wellObj->getName() + " " + wellObj->getCode()); listWellNames.append(wellObj->getName()); wellCodes.append(wellObj->getCode()); wellNameToObjMap.insert(wellObj->getName(), wellObj); } // 展示dialog供选择 nmWxSelectWellsDlg dlg; nmWxSelectWellsWidget wellListWidget; wellListWidget.setSelectedItems(wellPlotNameList); wellListWidget.addItems(listWellNames, wellCodes); dlg.setWidget(&wellListWidget); if(dlg.exec() == QDialog::Accepted) { // 用户点击了"确定"按钮 nmDataLogFile::getInstance()->writeLog(" OK "); QStringList wellNames = wellListWidget.getItems(); QList selectWellList; // 找出新选中的井 for(int i = 0; i < wellNames.count(); i++) { QString wellName = wellNames[i]; if (!wellName.isEmpty()) { // 确保井名不为空 // 仅将有效的井对象添加到 selectWellList selectWellList.append(wellNameToObjMap.value(wellName)); } } this->updateSelectedWells(selectWellList); // 更新完成后,通知参数界面刷新 //nmWxParameterProperty::notifyUpdateTable(); nmDataLogFile::getInstance()->writeLog("===" + wellNames.join(";") + "==="); } else { // 用户点击了"取消"按钮 nmDataLogFile::getInstance()->writeLog(" Cancel "); } } void nmSubWndMain::drawWell() { // 获取多边形边界的绘制,并模拟触发点击操作 // 目前多边形边界绘制是工具栏的第4个,所以用 3 // QList actions = m_pPlotToolBar->actions(); // if (!actions.isEmpty()) { // QAction *action = actions[0]; // action->trigger(); // } this->triggerToolBarAction(NMOT_Point_Well); nmDataLogFile::getInstance()->writeLog(" in drawWell "); } void nmSubWndMain::drawCrack() { this->triggerToolBarAction(NMOT_Line_Fracture); } void nmSubWndMain::drawRegion() { this->triggerToolBarAction(NMOT_Region); } void nmSubWndMain::drawRegionMark() { this->triggerToolBarAction(NMOT_RegionMark); } void nmSubWndMain::drawMeasure() { nmGuiPlot* plot = dynamic_cast(m_pWxPlot); QWidget* measureDlg = showMeasureDialog(); if(plot == nullptr || measureDlg == nullptr) { return; } bindMeasureDialog(measureDlg); plot->setAllPlotObjectsEditable(false); this->triggerToolBarAction(NMOT_Line_Measure); } void nmSubWndMain::drawGeoRef() { nmWxGeoRefDlg dlg(nullptr); dlg.exec(); } void nmSubWndMain::drawPointerPos() { nmGuiPlot* plot = dynamic_cast(m_pWxPlot); if(plot) { showPointerPosDialog(); } } bool nmSubWndMain::isDialogCmdOpened(int nId) const { return m_openDialogCmdIds.contains(nId); } void nmSubWndMain::markDialogCmdOpened(int nId) { if(!m_openDialogCmdIds.contains(nId)) { m_openDialogCmdIds.append(nId); } } void nmSubWndMain::markDialogCmdClosed(int nId) { // 从后向前遍历,避免索引错乱 for (int i = m_openDialogCmdIds.size() - 1; i >= 0; --i) { if (m_openDialogCmdIds[i] == nId) { m_openDialogCmdIds.remove(i); } } } void nmSubWndMain::onDialogCmdDestroyed(QObject* obj) { if(obj == nullptr) { return; } bool bOk = false; int nId = obj->property("dialogCmdId").toInt(&bOk); if(bOk) { markDialogCmdClosed(nId); } } void nmSubWndMain::bindDialogCmdDestroyed(QWidget* dialog, int nId) { if(dialog == nullptr) { return; } dialog->setProperty("dialogCmdId", nId); connect(dialog, SIGNAL(destroyed(QObject*)), this, SLOT(onDialogCmdDestroyed(QObject*))); } void nmSubWndMain::bindMeasureDialog(QWidget* measureDlg) { nmGuiPlot* plot = dynamic_cast(m_pWxPlot); if(plot == nullptr || measureDlg == nullptr) { return; } disconnect(plot, SIGNAL(sigMeasureStarted()), measureDlg, SLOT(resetButtons())); connect(plot, SIGNAL(sigMeasureStarted()), measureDlg, SLOT(resetButtons())); disconnect(measureDlg, SIGNAL(needDeleteMeasureObj()), plot, SLOT(finishMeasure())); connect(measureDlg, SIGNAL(needDeleteMeasureObj()), plot, SLOT(finishMeasure())); } QWidget* nmSubWndMain::showMeasureDialog() { nmGuiPlot* plot = dynamic_cast(m_pWxPlot); if(plot == nullptr) { return nullptr; } nmPlotDialogContextProvider* pDialogProvider = nmPlotDialogContext::provider(); if(pDialogProvider == nullptr) { return nullptr; } QWidget* measureDlg = pDialogProvider->createMeasureDialog(plot); if(measureDlg == nullptr) { return nullptr; } markDialogCmdOpened(5129); measureDlg->setObjectName("nmMeasureDialog"); measureDlg->setAttribute(Qt::WA_DeleteOnClose, true); bindDialogCmdDestroyed(measureDlg, 5129); nmDataMeasure* measureData = nmDataAnalyzeManager::getCurrentInstance()->getMeasureData(); if(measureData != nullptr) { connect(measureData, SIGNAL(sigMeasureDataChanged()), measureDlg, SLOT(updateDisplay())); } measureDlg->show(); return measureDlg; } QWidget* nmSubWndMain::showPointerPosDialog() { nmGuiPlot* plot = dynamic_cast(m_pWxPlot); if(plot == nullptr) { return nullptr; } nmPlotDialogContextProvider* pDialogProvider = nmPlotDialogContext::provider(); if(pDialogProvider == nullptr) { return nullptr; } QWidget* pointerPosDlg = pDialogProvider->createPointerPosDialog(plot); if(pointerPosDlg == nullptr) { return nullptr; } markDialogCmdOpened(5128); pointerPosDlg->setObjectName("nmPointerPosDialog"); pointerPosDlg->setAttribute(Qt::WA_DeleteOnClose, true); bindDialogCmdDestroyed(pointerPosDlg, 5128); plot->bindPointerPosDialog(pointerPosDlg); pointerPosDlg->show(); return pointerPosDlg; } void nmSubWndMain::generationMesh() { // // TODO,还不支持原型边界 // // 拿到多边形和点的位置信息 // QVector pObjVec = m_pWxPlot->getObjsByTag("nObjPolygonOutline"); // nmDataLogFile::getInstance()->writeLog(" ---------- " + QString::number(pObjVec.count())); // QVector pWellObjVec = m_pWxPlot->getObjsByTag("nObjPointWell"); // nmDataLogFile::getInstance()->writeLog(" ---------- " + QString::number(pWellObjVec.count())); // // 生成geo文件 // // 调用gmsh生成vtk文件 // // 弹出网格的dialog,渲染文件 // if(true) { // QDialog* dlg = new QDialog; // QVBoxLayout* layout = new QVBoxLayout; // dlg->setLayout(layout); // nmWxGridVTKContainerWidget* gridVTKContainerWidget = new nmWxGridVTKContainerWidget(dlg); // layout->addWidget(gridVTKContainerWidget); // dlg->resize(800, 600); // dlg->show(); // } } void nmSubWndMain::solveAndAnalyze() { // 关闭查看井数据对话框 if(m_resultDataDlg != nullptr) { delete m_resultDataDlg; m_resultDataDlg = nullptr; } // 强制清理旧的(以防万一上次没删掉) if (m_pProgressDlg != nullptr) { delete m_pProgressDlg; m_pProgressDlg = nullptr; } // 根据当前数据中心的分析切换到对应的流动段分析窗口 ZxMainWindow* pMainWnd1 = const_cast(m_pMainWindow); if(nullptr == pMainWnd1) { return; } ZxTabWidget* pTabWx = pMainWnd1->getCurTabWx(); iSubWndFitting* pSubWndFit = nmDataAnalyzeManager::getCurrentFitting(); Q_ASSERT(pSubWndFit != nullptr); if(pSubWndFit == nullptr) { return; } pTabWx->setCurrentWidget(pSubWndFit); // 调用求解器 QString sPostprocessingPath = ""; // 获取计算类型 NM_Grid_Type gridType = nmDataAnalyzeManager::getCurrentInstance()->getGridType(); // PEBI求解直接使用当前后处理目录 if(gridType == NM_Grid_PEBI) { //sPostprocessingPath = sPostprocessingPath + "/Pebi"; } // 以前由旧的DLL求解器单例阻止重复启动;删掉中间层后在这里保留同样的保护。 if(!s_pRunningSolverTask.isNull() && s_pRunningSolverTask->isRunning()) { QMessageBox::information(this, tr("solver error"), tr("task is running!")); return; } if(m_pSolverTask != nullptr) { // 上一次线程已结束但指针还未清空时,先交给Qt事件循环安全释放。 m_pSolverTask->deleteLater(); m_pSolverTask = nullptr; } // 直接创建真正执行DLL计算的PEBI线程任务,替代原来的中间转发层。 m_pSolverTask = new nmCalculationDllPebiSolverTask(sPostprocessingPath); s_pRunningSolverTask = m_pSolverTask; connect(m_pSolverTask, SIGNAL(sig_calculateDone(bool)), this, SLOT(on_solverTaskFinished(bool))); connect(m_pSolverTask, SIGNAL(finished()), m_pSolverTask, SLOT(deleteLater())); // 1. 创建并配置进度对话框 if (m_pProgressDlg == nullptr) { // TODO:关联到父窗口 m_pProgressDlg = new QProgressDialog(tr("Calculating, please wait..."), QString(), 0, 100, getMainWindow()); m_pProgressDlg->setWindowTitle(tr("Solver Progress")); m_pProgressDlg->setWindowModality(Qt::NonModal); // 模态,锁定父窗口 // 某些系统下,对话框右上角的关闭按钮可能仍存 // 使用 WindowFlags 彻底禁用关闭按钮 m_pProgressDlg->setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint); } m_pProgressDlg->setValue(0); m_pProgressDlg->show(); m_pProgressDlg->raise(); // 提升层级到最前 m_pProgressDlg->activateWindow(); // 激活窗口焦点 // 2. 初始化模拟进度逻辑 // 每次计算启动前,务必清零 m_nVirtualProgress = 0; m_nSlowDownCounter = 0; // 创建定时器 (如果不存在) if (m_pFakeProgressTimer == nullptr) { m_pFakeProgressTimer = new QTimer(this); connect(m_pFakeProgressTimer, SIGNAL(timeout()), this, SLOT(slotUpdateFakeProgress())); } // 3. 启动计算并开启模拟进度 m_pSolverTask->start(); m_pFakeProgressTimer->start(500); // 每 500 毫秒增加一次 } void nmSubWndMain::triggerToolBarAction(int index) { // 获取多边形边界的绘制,并模拟触发点击操作 // 目前多边形边界绘制是工具栏的第4个,所以用 3 if (m_pPlotToolBar == nullptr) return; QList actions = m_pPlotToolBar->actions(); if(!actions.isEmpty() && index >= 0 && index < actions.count()) { QAction *action = actions[index]; action->trigger(); } } void nmSubWndMain::mergeAnaResultToFitting() { // 渲染数据时弹出查看井数据的对话框 viewWellData(); //QMessageBox::information(this, tr("solver success"), tr("solver succeed!")); /*if (m_parameterPropertyWindow != nullptr) { delete m_parameterPropertyWindow; m_parameterPropertyWindow = nullptr; } m_parameterPropertyWindow = new nmWxParameterProperty(this); m_parameterPropertyWindow->show();*/ ZxMainWindow* pMainWnd1 = const_cast(m_pMainWindow); if(nullptr == pMainWnd1) { return; } iSubWndFitting* pSubWndFit = nmDataAnalyzeManager::getCurrentFitting(); Q_ASSERT(pSubWndFit != nullptr); if(pSubWndFit == nullptr) { return; } // 历史压力数据 QVector> vvecHistoryData; // 双对数数据 QVector> vvecLogPreData; // 半对数数据 QVector> vvecSemiLogPreData; nmDataAnalyzeManager* pInstance = nmDataAnalyzeManager::getCurrentInstance(); if(pInstance == nullptr) { return; } // 获取参与计算的井 QVector> vecWellsOrder = pInstance->getCalculationWells(); // 获取当前查看井的井名 nmDataWellBase* pCurWellData = pInstance->getCurWellData(); QString currentWellName; if(pCurWellData != nullptr) { currentWellName = pCurWellData->getWellName(); } // 判断当前井是否参与计算 if(!pInstance->isContainsWellName(currentWellName)) { for(int i = 0; i < vecWellsOrder.size(); i++) { // 跳过裂缝 if(vecWellsOrder[i].first == NM_WELL_MODEL::Unknow_Well) { continue; } // 未参与计算,选择展示第一口计算井的数据 currentWellName = vecWellsOrder[i].second; break; } } // PEBI结果按井名保存,直接读取当前井的三条结果曲线 nmDataWellBase* pWellData = NULL; if(pInstance->getGridType() == NM_Grid_PEBI) { pWellData = pInstance->findWellByName(currentWellName); if(pWellData == NULL) { return; } // 获取该井下存储的三条数据 vvecHistoryData = pWellData->getResultPressure(); vvecLogPreData = pWellData->getResultLogLog(); vvecSemiLogPreData = pWellData->getResultSemiLog(); } // 半对数 QVector vecHalfLog; this->inithalfLog(vvecSemiLogPreData, vecHalfLog, false); FitSubRstTag tag = FSRT_SemiLog; // 半对数 QString errorMessage; pSubWndFit->adjustFitSubPlotBy(tag, vecHalfLog, true, &errorMessage); // 双对数 QVector vecLogLog; this->initloglog(vvecLogPreData, vecLogLog, false); tag = FSRT_DoubleLog; pSubWndFit->adjustFitSubPlotBy(tag, vecLogLog, true, &errorMessage); // 历史压力曲线 QVector vecHistory; this->initPreHistory(vvecHistoryData, vecHistory, false); tag = FSRT_Hist; QString errorMessage4; pSubWndFit->adjustFitSubPlotBy(tag, vecHistory, true, &errorMessage4); // 更新结果基础网格,与当前实时生成的网格保持一致 pInstance->setResultBaseGrid(pInstance->getUnstructuredGridCopy()); QWidget* widget1 = pSubWndFit->getFitSubRstWxOf(FSRT_Nm3D, true, &errorMessage); // 创建 vtkWidget nmWxPostprocessingAnimationWidget* vtkWidget = nullptr; if(pInstance->getGridType() == NM_Grid_PEBI) { vtkWidget = new nmWxPostprocessingAnimationWidget(NULL); } if(widget1 == nullptr || vtkWidget == nullptr) { delete vtkWidget; return; } // 先清理 // 获取当前布局 QLayout* layout1 = widget1->layout(); if(layout1) { // 移除布局中的所有控件 QLayoutItem* item; while((item = layout1->takeAt(0))) { if(item->widget()) { // 删除控件 delete item->widget(); } delete item; // 删除布局项 } // 删除布局 delete layout1; } // 确保布局被移除 widget1->setLayout(nullptr); // 创建一个垂直布局管理器 QVBoxLayout* newLayout1 = new QVBoxLayout(widget1); // 将现有的控件添加到布局中 newLayout1->addWidget(vtkWidget); // 设置 widget 的布局 widget1->setLayout(newLayout1); // 结果参数界面 QWidget* widget2 = pSubWndFit->getFitSubRstWxOf(FSRT_NmRst, true, &errorMessage); if(widget2 == nullptr) { return; } // 创建结果参数界面 nmWxResultParameters* resultWidget = new nmWxResultParameters; // 先清理 // 获取当前布局 QLayout* layout2 = widget2->layout(); if(layout2) { // 移除布局中的所有控件 QLayoutItem* item; while((item = layout2->takeAt(0))) { if(item->widget()) { // 删除控件 delete item->widget(); } delete item; // 删除布局项 } // 删除布局 delete layout2; } // 确保布局被移除 widget2->setLayout(nullptr); // 创建一个垂直布局管理器 QVBoxLayout* newLayout2 = new QVBoxLayout(widget2); // 将现有的控件添加到布局中 newLayout2->addWidget(resultWidget); // 设置 widget 的布局 widget2->setLayout(newLayout2); //nmWxResultParameters* resultWidget = new nmWxResultParameters; //resultWidget->show(); } bool nmSubWndMain::inithalfLog(QVector> & vvecLogPreData, QVector& vecDescs, bool isHistoryData) { // 半对数压力曲线 iCurveDesc curveDesc; if(vvecLogPreData.size() != 2) { vecDescs.append(curveDesc); return false; } // X轴数据 curveDesc.m_vecX = vvecLogPreData[0]; // Y轴数据 curveDesc.m_vecY = vvecLogPreData[1]; curveDesc.m_oCurveType = POT_CurvePressure; // 判断是历史数据还是计算数据 if(isHistoryData) { curveDesc.m_sCurveName = s_SemiSouce_Curve; curveDesc.m_bLineVisible = false; // 关闭线模式可见性 curveDesc.m_bPointVisible = true; // 开启点模式可见性 curveDesc.m_oDot.setColor(Qt::red); // 设置点的颜色 curveDesc.m_oDot.setStyle(ZxDotType::DTS_Cross); // x形状 } else { curveDesc.m_sCurveName = s_SemiTheorySouce_Curve; // 理论曲线 curveDesc.m_bLineVisible = true; // 开启线模式可见性 curveDesc.m_bPointVisible = false; // 关闭点模式可见性 curveDesc.m_oPen.setColor(Qt::green); // 设置线的颜色 } // 将 curveDesc 添加到 QVector vecDescs.append(curveDesc); return true; } bool nmSubWndMain::initloglog(QVector > &vvecLogPreData, QVector& vecDescs, bool isHistoryData) { // 双对数压力曲线 iCurveDesc curveDesc1, curveDesc2; if(vvecLogPreData.size() != 3) { vecDescs.append(curveDesc1); vecDescs.append(curveDesc2); return false; } // 确保每个内部 QVector 都不为空,然后移除其最后一个元素 // 移除 vvecLogPreData[0] (vX) 中的最后一个元素 if(!vvecLogPreData[0].isEmpty()) { vvecLogPreData[0].remove(vvecLogPreData[0].size() - 1); } else { return false; } // 移除 vvecLogPreData[1] (vY) 中的最后一个元素 if(!vvecLogPreData[1].isEmpty()) { vvecLogPreData[1].remove(vvecLogPreData[1].size() - 1); } else { return false; } // 移除 vvecLogPreData[2] (vZ) 中的最后一个元素 if(!vvecLogPreData[2].isEmpty()) { vvecLogPreData[2].remove(vvecLogPreData[2].size() - 1); } else { return false; } // 曲线1 curveDesc1.m_vecX = vvecLogPreData[0]; curveDesc1.m_vecY = vvecLogPreData[1]; // 曲线2 curveDesc2.m_vecX = vvecLogPreData[0]; curveDesc2.m_vecY = vvecLogPreData[2]; curveDesc1.m_oCurveType = POT_CurveDiscrete; curveDesc2.m_oCurveType = POT_CurveDiscrete; // 判断是历史数据还是计算数据 if(isHistoryData) { curveDesc1.m_sCurveName = s_Souce_Curve; curveDesc2.m_sCurveName = s_Deriv_Curve; curveDesc1.m_bLineVisible = false; // 关闭线模式可见性 curveDesc1.m_bPointVisible = true; // 开启点模式可见性 curveDesc1.m_oDot.setColor(Qt::green); // 设置点的颜色 curveDesc1.m_oDot.setStyle(ZxDotType::DTS_Cross); // X形状 curveDesc2.m_bLineVisible = false; // 关闭线模式可见性 curveDesc2.m_bPointVisible = true; // 开启点模式可见性 curveDesc2.m_oDot.setColor(Qt::red); // 设置点的颜色 curveDesc2.m_oDot.setStyle(ZxDotType::DTS_Circle); // O形状 curveDesc2.m_oDot.setFilling(false); // 不填充 } else { curveDesc1.m_sCurveName = s_TheorySouce_Curve; curveDesc2.m_sCurveName = s_TheoryDeriv_Curve; curveDesc1.m_bLineVisible = true; // 关闭线模式可见性 curveDesc1.m_bPointVisible = false; // 开启点模式可见性 curveDesc1.m_oPen.setColor(Qt::red); // 设置线的颜色 curveDesc2.m_bLineVisible = true; // 关闭线模式可见性 curveDesc2.m_bPointVisible = false; // 开启点模式可见性 curveDesc2.m_oPen.setColor(Qt::green); // 设置线的颜色 } // 将 curveDesc 添加到 QVector vecDescs.append(curveDesc1); // 将 curveDesc 添加到 QVector vecDescs.append(curveDesc2); return true; } bool nmSubWndMain::initPreHistory(QVector > &vvecHistoryData, QVector& vecDescs, bool isHistoryData) { // 压力曲线 iCurveDesc curveDesc; if(vvecHistoryData.size() != 2) { vecDescs.append(curveDesc); return false; } // X轴数据 curveDesc.m_vecX = vvecHistoryData[0]; // Y轴数据 curveDesc.m_vecY = vvecHistoryData[1]; curveDesc.m_oCurveType = POT_CurvePressure; // 判断是历史数据还是计算数据 if(isHistoryData) { curveDesc.m_sCurveName = s_HistorySouce_CurveP; curveDesc.m_bLineVisible = false; // 关闭线模式可见性 curveDesc.m_bPointVisible = true; // 开启点模式可见性 curveDesc.m_oDot.setColor(Qt::red); // 设置点的颜色 curveDesc.m_oDot.setStyle(ZxDotType::DTS_Plus); // +形状 } else { curveDesc.m_sCurveName = s_HistoryFit_CurveP; curveDesc.m_bLineVisible = true; // 关闭线模式可见性 curveDesc.m_bPointVisible = false; // 开启点模式可见性 curveDesc.m_oPen.setColor(Qt::green); // 设置线的颜色 } // 将 curveDesc 添加到 QVector vecDescs.append(curveDesc); return true; } bool nmSubWndMain::onConfirmClosing() { return iSubWndBaseAF::onConfirmClosing(); } void nmSubWndMain::reservoirCharacteristics() { nmWxReservoirPropertiesDlg dlg; dlg.exec(); // TODO: 修改完参数应该刷新画布 } void nmSubWndMain::geoLayering() { nmWxGeometryLayerDlg dlg; if(dlg.exec() == QDialog::Rejected) { return; } else { QVector layers = dlg.getLayerData(); // 添加到数据中心 nmDataAnalyzeManager::getCurrentInstance()->setLayers(layers); //for (int i = 0; i < layers.size(); ++i) { // nmDataLayer* layer = layers[i]; // qDebug() << "Layer" << i + 1 << "Top:" << layer->getTop() // << "Bottom:" << layer->getBottom() // << "Thickness:" << layer->getThickness() // << "IsChecked:" << layer->getIsChecked(); //} } } void nmSubWndMain::on_calculationFinished(NM_Calculation_Result result) { // 1. 立即停止模拟定时器(防止它在处理结果时继续触发) if (m_pFakeProgressTimer) { m_pFakeProgressTimer->stop(); } // 2. 强制拉满进度条(给用户一个成功的反馈) if (m_pProgressDlg) { m_pProgressDlg->setValue(100); } // 3. 处理计算结果 if(result == NM_Calculation_Result_Success) { // 创建结果对象,显示曲线 nmDataAnalyzeManager::getCurrentInstance()->createMixedResult(); this->mergeAnaResultToFitting(); } else { // 如果失败,进度条其实没必要拉满了,直接提示错误 QMessageBox::warning(this, tr("solver error"), tr("solver failed!")); } // 4. 直接销毁对象并置空 if (m_pProgressDlg != nullptr) { delete m_pProgressDlg; m_pProgressDlg = nullptr; } } void nmSubWndMain::on_solverTaskFinished(bool isSuccessed) { // 线程完成后清空两个持有点:当前窗口指针和全局运行中指针。 nmCalculationDllPebiSolverTask* pTask = qobject_cast(sender()); if(pTask == m_pSolverTask) { m_pSolverTask = nullptr; } if(pTask == s_pRunningSolverTask) { s_pRunningSolverTask = nullptr; } // 保持旧流程不变:bool结果转换为计算结果枚举,再交给原来的统一后处理函数。 NM_Calculation_Result result = isSuccessed ? NM_Calculation_Result_Success : NM_Calculation_Result_Fail; this->on_calculationFinished(result); } void nmSubWndMain::deleteOneObj() { this->triggerToolBarAction(NMOT_Delete); } void nmSubWndMain::setLocked() { if(m_lockState) { // 锁定 m_lockState = false; int objCount = this->m_pWxPlot->m_pPlot->getObjCount(); for(int i = 0; i < objCount; i++) { ZxObjBase* obj = this->m_pWxPlot->m_pPlot->getObjByIndex(i); if(!_isSame("nObjPointWell", obj->getTagName())) { obj->setReadOnly(false); obj->setLockPos(false); } } QStringList nIDs; nIDs.append("5125"); nIDs.append("5124"); nIDs.append("5123"); nIDs.append("5114"); nIDs.append("5115"); nIDs.append("5116"); nIDs.append("5117"); nIDs.append("5118"); nIDs.append("5119"); nIDs.append("5102"); nIDs.append("5120"); nIDs.append("5103"); nIDs.append("5104"); nIDs.append("5105"); nIDs.append("5106"); nIDs.append("5107"); nIDs.append("5108"); nIDs.append("5109"); nIDs.append("5110"); nIDs.append("5111"); nIDs.append("5121"); nIDs.append("5112"); nIDs.append("5113"); nIDs.append("5122"); nIDs.append("9002"); nIDs.append("9003"); nIDs.append("9101"); nIDs.append("9102"); nIDs.append("9103"); nIDs.append("9104"); nIDs.append("3104"); emit sigFreshRnStates(nIDs); /* if (m_pMainWindow != NULL) { //m_pMainWindow->slotFreshRnStates(nIDs); } */ //m_pMainWindow->getMainRibbon } else { m_lockState = true; int objCount = this->m_pWxPlot->m_pPlot->getObjCount(); for(int i = 0; i < objCount; i++) { ZxObjBase* obj = this->m_pWxPlot->m_pPlot->getObjByIndex(i); if(!_isSame("nObjPointWell", obj->getTagName())) { obj->setReadOnly(true); obj->setLockPos(true); } } QStringList nIDs; nIDs.append("5125"); nIDs.append("5124"); nIDs.append("5123"); nIDs.append("5114"); nIDs.append("5115"); nIDs.append("5116"); nIDs.append("5117"); nIDs.append("5118"); nIDs.append("5119"); nIDs.append("5102"); nIDs.append("5120"); nIDs.append("5103"); nIDs.append("5104"); nIDs.append("5105"); nIDs.append("5106"); nIDs.append("5107"); nIDs.append("5108"); nIDs.append("5109"); nIDs.append("5110"); nIDs.append("5111"); nIDs.append("5121"); nIDs.append("5112"); nIDs.append("5113"); nIDs.append("5122"); //nIDs.append("9002"); //nIDs.append("9003"); nIDs.append("9101"); nIDs.append("9102"); nIDs.append("9103"); nIDs.append("9104"); nIDs.append("3104"); emit sigFreshRnStates(nIDs); /* if (m_pMainWindow != NULL) { m_pMainWindow->slotFreshRnStates(nIDs); } */ /* emit sigFreshRnStates(nIDs); if (m_pMainWindow != NULL) { m_pMainWindow->slotFreshRnStates(nIDs); } bool b; QString sName = "NmUnlocked"; int nID = 5119; bool bLicensed; nmSubWndMain::checkCmdEnable(b, sName, nID, bLicensed); nID = 5125; sName = "NmPrint"; nmSubWndMain::checkCmdEnable(b, sName, nID, bLicensed); */ } } nmGuiPlot * nmSubWndMain::getWxPlot() const { return m_pWxPlot; } void nmSubWndMain::onProgressUpdated(int progress) { if (!m_pProgressDlg) { return; } // 1. 处理特殊结束信号 if (progress >= 100 || progress == -1) { // 停止模拟定时器,防止它继续累加 if (m_pFakeProgressTimer && m_pFakeProgressTimer->isActive()) { m_pFakeProgressTimer->stop(); } m_pProgressDlg->setValue(100); return; } // 2. 进度倒退保护 // 如果模拟进度已经跑到了 50%,但某个真实信号传回来 40%, // 为了防止进度条“倒着走”引起用户困惑,只有当前值更大时才更新。 if (progress > m_pProgressDlg->value()) { m_pProgressDlg->setValue(progress); // 同步更新模拟变量,防止定时器下次触发时使用旧值 m_nVirtualProgress = progress; } } void nmSubWndMain::viewWellData() { // 1.获取当前查看井的井名(默认选中) nmDataWellBase* pCurWellData = nmDataAnalyzeManager::getCurrentInstance()->getCurWellData(); QString currentWellName; if(pCurWellData != nullptr) { currentWellName = pCurWellData->getWellName(); } // 2.找到计算了的井 QVector> vecWellsOrder = nmDataAnalyzeManager::getCurrentInstance()->getCalculationWells(); // 统计真实参与计算的井数量,Unknow_Well 在这里是裂缝等非井项。 int nWellCount = 0; for(int i = 0; i < vecWellsOrder.size(); i++) { if(vecWellsOrder[i].first != NM_WELL_MODEL::Unknow_Well) { nWellCount++; } } // 释放内存 if(m_resultDataDlg != nullptr) { delete m_resultDataDlg; m_resultDataDlg = nullptr; } // 只有一口井时不需要弹出选择井窗口,直接结束选择流程。 if(nWellCount <= 1) { return; } // 3.创建对话框和井列表控件 m_resultDataDlg = new nmWxSelectResultWellsDlg; nmWxSelectResultWellsWidget *wellListWidget = new nmWxSelectResultWellsWidget; // 4.添加所有参与计算的井 for(int i = 0; i < vecWellsOrder.size(); i++) { // 跳过裂缝 if(vecWellsOrder[i].first == NM_WELL_MODEL::Unknow_Well) { continue; } wellListWidget->addItem(vecWellsOrder[i].second); } // 5.设置当前选中的井 if(nmDataAnalyzeManager::getCurrentInstance()->isContainsWellName(currentWellName)) { // 当前井参与计算,直接选择当前井 wellListWidget->setSelectedItem(currentWellName); } else { // 当前井没有参与计算,选择参与计算的第一口井 wellListWidget->setSelectedItem(vecWellsOrder[0].second); for(int i = 0; i < vecWellsOrder.size(); i++) { // 跳过裂缝 if(vecWellsOrder[i].first == NM_WELL_MODEL::Unknow_Well) { continue; } wellListWidget->setSelectedItem(vecWellsOrder[i].second); break; } } // 6.设置控件并连接信号 m_resultDataDlg->setWidget(wellListWidget); connect(m_resultDataDlg, SIGNAL(wellSelected(QString)), this, SLOT(onWellSelected(QString))); // 7.显示对话框 m_resultDataDlg->show(); } void nmSubWndMain::onWellSelected(const QString& wellName) { nmDataAnalyzeManager* pInstance = nmDataAnalyzeManager::getCurrentInstance(); if(pInstance == nullptr) { return; } // 更新数据中心的当前查看井数据 nmDataWellBase* pCurWellData = pInstance->getCurWellData(); if(pCurWellData == nullptr) return; // 查找切换后的井数据 nmDataWellBase* pWellData = NULL; pWellData = pInstance->findWellByName(wellName); if(pWellData == NULL) return; if(pCurWellData->getWellName() != wellName) { // 设置为当前查看井数据 pInstance->setCurWellData(pWellData); } // 1.获取流动段分析窗口 iSubWndFitting* pSubWndFit = nmDataAnalyzeManager::getCurrentFitting(); Q_ASSERT(pSubWndFit != nullptr); if(!pSubWndFit) return; // 2.根据选择的井名获取计算数据 QVector> vvecHistoryData; QVector> vvecLogPreData; QVector> vvecSemiLogPreData; if(pInstance->getGridType() == NM_Grid_PEBI) { vvecHistoryData = pWellData->getResultPressure(); vvecLogPreData = pWellData->getResultLogLog(); vvecSemiLogPreData = pWellData->getResultSemiLog(); } // 调用函数 QVector> vvecHistoryPressureData; //压力历史数据 QVector> vvecHistoryLogData; // 历史双对数曲线数据 QVector> vvecHistorySemiLogData; // 历史半对数曲线数据 pInstance->calculationLogData(pWellData, vvecHistoryPressureData, vvecHistoryLogData, vvecHistorySemiLogData); // 删除末尾无效元素 //if (!vvecHistoryLogData.empty() && // vvecHistoryLogData.size() >= 3 && // 确保有3个子数组 // !vvecHistoryLogData[0].empty() && // 检查x数组非空 // !vvecHistoryLogData[1].empty() && // 检查y数组非空 // !vvecHistoryLogData[2].empty()) { // 检查z数组非空 // // 同时删除x、y、z的最后一个数据点 // vvecHistoryLogData[0].removeLast(); // 删除最后一个x // vvecHistoryLogData[1].removeLast(); // 删除最后一个y // vvecHistoryLogData[2].removeLast(); // 删除最后一个z //} // 窗口标识,半对数、双对数、历史压力 FitSubRstTag tag; // 错误信息 QString errorMessage; // 3、半对数曲线 QVector vecHistoryHalfLog; this->inithalfLog(vvecHistorySemiLogData, vecHistoryHalfLog, true); tag = FSRT_SemiLog; // 删除原来的线,并将当前查看井的历史半对数曲线渲染出来 pSubWndFit->adjustFitSubPlotBy(tag, vecHistoryHalfLog, true, &errorMessage); //计算出来的半对数数据,同样需要删除原来的 QVector vecHalfLog; this->inithalfLog(vvecSemiLogPreData, vecHalfLog, false); pSubWndFit->adjustFitSubPlotBy(tag, vecHalfLog, true, &errorMessage); // 双对数 QVector vecHistoryLog; this->initloglog(vvecHistoryLogData, vecHistoryLog, true); tag = FSRT_DoubleLog; // 删除原来的线,并将当前查看井的历史双对数曲线渲染出来 pSubWndFit->adjustFitSubPlotBy(tag, vecHistoryLog, true, &errorMessage); //计算出来的双对数数据,同样需要删除原来的 QVector vecLogLog; this->initloglog(vvecLogPreData, vecLogLog, false); pSubWndFit->adjustFitSubPlotBy(tag, vecLogLog, true, &errorMessage); // 历史压力曲线 QVector vecHistoryPre; this->initPreHistory(vvecHistoryPressureData, vecHistoryPre, true); tag = FSRT_Hist; // 删除原来的线,并将当前查看井的历史压力曲线渲染出来 pSubWndFit->adjustFitSubPlotBy(tag, vecHistoryPre, true, &errorMessage); //计算出来的压力数据,同样需要删除原来的 QVector vecHistory; this->initPreHistory(vvecHistoryData, vecHistory, false); pSubWndFit->adjustFitSubPlotBy(tag, vecHistory, true, &errorMessage); } #include //void nmSubWndMain::calculationLogData( // nmDataWellBase* pWellData, // QVector>& vvecHistoryData, // QVector>& vvecLogPreData, // QVector>& vvecSemiLogPreData) //{ // // 清空输出参数 // vvecHistoryData.clear(); // vvecLogPreData.clear(); // vvecSemiLogPreData.clear(); // // if(pWellData == nullptr) { // return; // } // // // 初始化二维数组结构 // vvecHistoryData.resize(2); // [0]=x, [1]=y // vvecLogPreData.resize(3); // [0]=x, [1]=y, [2]=z // vvecSemiLogPreData.resize(2); // [0]=x, [1]=pointData[0] // // // 准备压力数据 // QVector vecPressure = pWellData->getPressurePoints(); // std::vector wellPressureData; // // // 填充 wellPressureData 和 vvecHistoryData // foreach(const QPointF& qpoint, vecPressure) { // // wellPressureData // Point pt; // pt.x = qpoint.x(); // pt.y = qpoint.y(); // pt.z = 0.0; // wellPressureData.push_back(pt); // // // vvecHistoryData // vvecHistoryData[0].append(qpoint.x()); // x // vvecHistoryData[1].append(qpoint.y()); // y // } // // // 准备流量段数据 // QVector vecTimeQ = pWellData->getFlowPoints(); // int nTimeNumQ = vecTimeQ.size() - 1; // std::vector timeQ(nTimeNumQ); // std::vector q(nTimeNumQ); // // for(int i = 0; i < nTimeNumQ; ++i) { // timeQ[i] = vecTimeQ[i + 1].x(); // q[i] = vecTimeQ[i + 1].y(); // } // // // 调用 DLL 计算双对数曲线 // std::vector logPre; // int iSectionFlowIndex = pWellData->getIndexF(); // // HMODULE hMod_solver = LoadLibrary(L"singlePhaseSolverDll.dll"); // // if(hMod_solver) { // typedef bool (*PreLog)(const std::vector&, const int&, double*, double*, int, std::vector&); // PreLog preLogFun = (PreLog)GetProcAddress(hMod_solver, "logLogPre"); // // if(nullptr == preLogFun) { // FreeLibrary(hMod_solver); // std::cout << "preLogFun failed!\n"; // return; // } // // preLogFun(wellPressureData, iSectionFlowIndex, timeQ.data(), q.data(), nTimeNumQ, logPre); // // // 不添加最后一个元素 // for(uint i = 0; i < logPre.size() - 1; i++) { // //logFile << logPre[i].x << "\t" << logPre[i].y << "\t" << logPre[i].z << "\t" << std::endl; // vvecLogPreData[0].append(logPre[i].x); // x // vvecLogPreData[1].append(logPre[i].y); // y // vvecLogPreData[2].append(logPre[i].z); // z // } // // // 填充半对数曲线数据 (x, pointData[0]) // foreach(const auto& point, logPre) { // vvecSemiLogPreData[0].append(point.x); // x // double y_value = point.pointData.empty() ? 0.0 : point.pointData[0]; // vvecSemiLogPreData[1].append(y_value); // pointData[0] 或默认值 // } // FreeLibrary(hMod_solver); // } //} void nmSubWndMain::onGenerateButtonClicked() { //QString sDir = ZxBaseUtil::getCurWellDirOf("Nm/PreProcessing"); if(nmDataAnalyzeManager::getCurrentInstance()->getGridType() == NM_Grid_PEBI) { nmCalculationPebiGrid* pPebiGridGeneratorInstance = nmCalculationPebiGrid::getInstance(); if(pPebiGridGeneratorInstance->getGridOutput2().Trinodexy.size() <= 0) { // 没有可用PEBI网格时才重新生成 if(!pPebiGridGeneratorInstance->meshGenPebi()) { return; } } // 求解计算 this->solveAndAnalyze(); } } void nmSubWndMain::slotUpdateFakeProgress() { // --- 1. 安全防御检查 --- // 如果进度对话框已被销毁(例如计算提前结束或用户关闭),立即停止定时器并退出 // 防止在 delete 对象后发生野指针访问崩溃 if (m_pProgressDlg == nullptr) { if (m_pFakeProgressTimer) { m_pFakeProgressTimer->stop(); } return; } // --- 2. 分段模拟进度逻辑 (0% - 99%) --- // 采用“前快后慢”的心理学策略,50% 之后逐级增加阻力,为 DLL 计算留出缓冲时间 if (m_nVirtualProgress < 99) { // 步进计数器,用于实现非匀速增长 m_nSlowDownCounter++; if (m_nVirtualProgress < 50) { // [第一阶段] 0% - 50%: 快速增长 // 每次定时器触发(500ms)即增加 1%,给予用户“响应迅速”的反馈 m_nVirtualProgress += 1; } else if (m_nVirtualProgress < 75) { // [第二阶段] 50% - 75%: 第一次减速 // 每触发 4 次(约 2秒)增加 1%,模拟进入核心计算阶段 if (m_nSlowDownCounter % 4 == 0) { m_nVirtualProgress += 1; } } else if (m_nVirtualProgress < 90) { // [第三阶段] 75% - 90%: 第二次减速 // 每触发 8 次(约 4秒)增加 1%,应对较大规模的数据处理 if (m_nSlowDownCounter % 8 == 0) { m_nVirtualProgress += 1; } } else { // [第四阶段] 90% - 99%: 深度减速 (极慢) // 每触发 15 次(约 7.5秒)增加 1%。此时进度条几乎“爬行”, // 旨在确保在 DLL 返回完成信号前,进度条不会提前撞击 100% if (m_nSlowDownCounter % 15 == 0) { m_nVirtualProgress += 1; } } // 统一调用更新接口,同步 UI 显示 this->onProgressUpdated(m_nVirtualProgress); } else { // --- 3. 终点停靠 --- // 到达 99% 时停止自动增长,死等来自 Solver 线程的真正的 Finished 信号 if (m_pFakeProgressTimer) { m_pFakeProgressTimer->stop(); } } } void nmSubWndMain::generateDFN() { nmWxDFN dfnDialog(nullptr); dfnDialog.exec(); } void nmSubWndMain::displaySetting() { nmWxDisplaySettings disPlayDlg; disPlayDlg.exec(); } void nmSubWndMain::updateMapByDataManager(nmDataAnalyzeManager* pDataManager) { // 删除原来的图元信息 if(m_pWxPlot == nullptr) { return; } // 更新对应的Plot成员变量 pDataManager->setPlot(m_pWxPlot); m_pWxPlot->deleteAllPlotObjs(); // 根据数据中心内容绘制新图元 m_pWxPlot->setPlotsByDataManger(pDataManager); }