#include "zxLogInstance.h" #include "ZxBaHelper.h" #include "ZxResolutionHelper.h" #include "zxSysUtils.h" #include "ZxPtyDock.h" #include "iDockBaseWx.h" #include "ZxMainWindow.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" #ifdef QT_DEBUG #include "ZxDataGaugeP.h" #endif #ifdef QT_DEBUG #include "nmXmlHelper.h" #endif #include "nmSubWndGrid.h" #include "nmDataDemo.h" #include "nmDataLogFile.h" #include "nmGuiPlot.h" #include "nmWxGridVTKContainerWidget.h" #include "nmCalculationUtils.h" #include "nmCalculationPebiGrid.h" #include "nmCalculationPebiGridTask.h" #include "nmDataAnalyzeManager.h" #include "QListWidget.h" #include #include #include #include "ZxRstWnd.h" nmSubWndGrid::nmSubWndGrid(QWidget *parent, QString sExt, double pebiGridControl, bool bGeneratePebiGrid, nmDataAnalyzeManager* pDataManager) : iSubWndBaseFit(parent, sExt), m_mainLayout(nullptr), m_vtkWidget(nullptr), m_pDebounceTimer(nullptr), m_pDataManager(pDataManager), m_pGridTask(nullptr), m_bGridUpdatePending(false), m_dPebiGridControl(pebiGridControl), m_bGeneratePebiGrid(bGeneratePebiGrid) { m_sMdiWndType = s_MdiType_DataAnal; setWindowTitle(tr("nmSubWndGrid")); } nmSubWndGrid::~nmSubWndGrid() { // 外部 DLL 不支持安全中止;窗口析构前等待自己的任务退出,避免销毁运行中的 QThread。 if(!m_pGridTask.isNull() && m_pGridTask->isRunning()) { disconnect(m_pGridTask, nullptr, this, nullptr); m_pGridTask->wait(); } } void nmSubWndGrid::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(); } bool nmSubWndGrid::loadRsts() { return true; } bool nmSubWndGrid::saveRsts() { ZxRstWnd* pRstWnd = this->getRstUtilWnd(); if (nullptr == pRstWnd) { return false; } return pRstWnd->save(); } bool nmSubWndGrid::onConfirmClosing() { // 先走基类关闭确认;用户取消关闭时不清理网格数据。 if(!iSubWndBaseFit::onConfirmClosing()) { return false; } nmCalculationPebiGrid::getInstance()->clearGridData(m_pDataManager.data()); nmDataAnalyzeManager* pDataManager = m_pDataManager.data(); if(pDataManager != nullptr) { // 当前窗口选择清除网格缓存后,分析方案也必须同步失效。 pDataManager->invalidatePebiGrid(); pDataManager->clearUnstructuredGrid(); } return true; } void nmSubWndGrid::initUI() { QWidget* mainWidget = new QWidget(this); // 设置 mainWidget 的布局和尺寸策略 mainWidget->setLayout(new QVBoxLayout(mainWidget)); // 确保 mainWidget 有自己的布局 mainWidget->layout()->setContentsMargins(0, 0, 0, 0); // 移除边距 mainWidget->layout()->setSpacing(0); // 移除间距 mainWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // 扩展策略 setCentralWidget(mainWidget); // m_mainLayout 应该直接是 mainWidget 的布局 m_mainLayout = qobject_cast(mainWidget->layout()); // 当前不是加载进来的网格,都需要根据Map几何生成新的PEBI网格 if (m_bGeneratePebiGrid) { generatePebiGrid(); } m_vtkWidget = new nmWxGridVTKContainerWidget(m_pDataManager.data(), this); m_vtkWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // 扩展策略 m_mainLayout->addWidget(m_vtkWidget); // 首次创建 //if(generatePebiGrid()) { // // nmWxGridVTKContainerWidget 的尺寸策略 // m_vtkWidget = new nmWxGridVTKContainerWidget(this); // m_vtkWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // 扩展策略 // m_mainLayout->addWidget(m_vtkWidget); //} } QWidget* nmSubWndGrid::initUiMainWx() { return nullptr; } bool nmSubWndGrid::runCmdBy(QString sName, QString sID) { if(sID.toInt() == 5401) { return true; } return false; } bool nmSubWndGrid::generatePebiGrid() { // PEBI网格 nmCalculationPebiGrid* pPebiGridGeneratorInstance = nmCalculationPebiGrid::getInstance(); // 当前流程只保留PEBI网格;这里仍写入数据中心,供求解和后处理的旧判断继续使用。 nmDataAnalyzeManager* pDataManager = m_pDataManager.data(); if(pDataManager == nullptr) { return false; } pDataManager->setGridType(NM_Grid_PEBI); // 将对话框中的GridControl传给PEBI输入参数GridControl pPebiGridGeneratorInstance->setGridControl(m_dPebiGridControl, pDataManager); // 生成PEBI非结构化网格对象 return pPebiGridGeneratorInstance->meshGenPebi(pDataManager); } void nmSubWndGrid::updateGrid() { // 角色、产量等只影响求解的变化也会发送 dataChanged;网格仍有效时无需重划。 nmDataAnalyzeManager* pDataManager = m_pDataManager.data(); if(pDataManager != nullptr && pDataManager->isPebiGridValid()) { return; } // dataChanged可能连续触发,使用当前窗口自己的定时器合并为一次网格重建 if(!m_pDebounceTimer) { m_pDebounceTimer = new QTimer(this); m_pDebounceTimer->setSingleShot(true); // 单次触发 connect(m_pDebounceTimer, SIGNAL(timeout()), this, SLOT(onDebounceTimeout())); } m_pDebounceTimer->start(500); // 500ms 防抖 } void nmSubWndGrid::onDebounceTimeout() { // 第一步:同一窗口只允许一个网格线程运行,连续编辑合并为下一次重建。 if(!m_pGridTask.isNull() && m_pGridTask->isRunning()) { m_bGridUpdatePending = true; return; } nmDataAnalyzeManager* pDataManager = m_pDataManager.data(); if(pDataManager == nullptr) { return; } // 第二步:把窗口参数写回所属分析方案,再启动绑定同一管理器的后台任务。 nmCalculationPebiGrid::getInstance()->setGridControl( m_dPebiGridControl, pDataManager); m_pGridTask = new nmCalculationPebiGridTask(pDataManager, this); connect(m_pGridTask, SIGNAL(pebiGridGenerated(bool)), this, SLOT(onPebiGridGenerated(bool))); connect(m_pGridTask, SIGNAL(finished()), this, SLOT(onPebiGridTaskFinished())); connect(m_pGridTask, SIGNAL(finished()), m_pGridTask, SLOT(deleteLater())); m_pGridTask->start(); } void nmSubWndGrid::onPebiGridGenerated(bool success) { if (!success) { return; } // 删除旧的 VTK 控件 if (m_vtkWidget) { m_mainLayout->removeWidget(m_vtkWidget); delete m_vtkWidget; m_vtkWidget = nullptr; } // 创建新的 VTK 控件,并将其加入布局 m_vtkWidget = new nmWxGridVTKContainerWidget(m_pDataManager.data(), this); // 设置新创建的 nmWxGridVTKContainerWidget 的尺寸策略** m_vtkWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // 扩展策略 m_mainLayout->addWidget(m_vtkWidget); } void nmSubWndGrid::onPebiGridTaskFinished() { // 第一步:只清理由当前窗口持有的任务,避免旧 finished 信号覆盖新任务指针。 if(sender() == m_pGridTask.data()) { m_pGridTask = nullptr; } // 第二步:运行期间若又有数据变化,重新启动防抖计时,只补做最后一次网格。 if(m_bGridUpdatePending) { m_bGridUpdatePending = false; updateGrid(); } }