#include "nmWxDFN.h" #include #include #include #include #include #include #include "nmWxDFNGenerateDlg.h" #include "nmWxDFNLoadFromFile.h" #include "nmWxDFNExportDlg.h" #include "nmDataAnalyzeManager.h" #include "nmGuiPlot.h" // 构造函数 nmWxDFN::nmWxDFN(QWidget *parent) : QDialog(parent) { setWindowTitle(tr("DFN")); setMinimumSize(516, 519); // 从数据中心获取DFN数据 m_vecDFNData = nmDataAnalyzeManager::getCurrentInstance()->getDFNFractureDataList(); qsrand(QTime::currentTime().msec()); this->initUI(); this->initConnections(); updateButtonsState(); m_originType = None; } nmWxDFN::~nmWxDFN() { } void nmWxDFN::initUI() { QVBoxLayout *pMainLayout = new QVBoxLayout(this); pMainLayout->setSpacing(15); // 增加组件间距 // 操作按钮组 QHBoxLayout *pButtonLayout = new QHBoxLayout(); // 创建包含按钮和标签的Widget m_pLoadButtonWidget = new QWidget(this); m_pGenerateButtonWidget = new QWidget(this); m_pDeleteButtonWidget = new QWidget(this); m_pExportButtonWidget = new QWidget(this); m_pLoadButton = new QPushButton(m_pLoadButtonWidget); m_pGenerateButton = new QPushButton(m_pGenerateButtonWidget); m_pDeleteButton = new QPushButton(m_pDeleteButtonWidget); m_pExportButton = new QPushButton(m_pExportButtonWidget); m_pLoadButtonLabel = new QLabel(tr("Load"), m_pLoadButtonWidget); m_pGenerateButtonLabel = new QLabel(tr("Generate"), m_pGenerateButtonWidget); m_pDeleteButtonLabel = new QLabel(tr("Delete"), m_pDeleteButtonWidget); m_pExportButtonLabel = new QLabel(tr("Export"), m_pExportButtonWidget); QString appDir = QCoreApplication::applicationDirPath(); appDir = appDir.section('/', 0, -2); // 获取上一级目录 // 设置按钮图标 QIcon loadIcon(appDir + "/Res/Icon/NmDFNLoad.png"); QIcon generateIcon(appDir + "/Res/Icon/NmDFNGenerate.png"); QIcon deleteIcon(appDir + "/Res/Icon/NmDFNDelete.png"); QIcon exportIcon(appDir + "/Res/Icon/NmDFNExport.png"); m_pLoadButton->setIcon(loadIcon); m_pGenerateButton->setIcon(generateIcon); m_pDeleteButton->setIcon(deleteIcon); m_pExportButton->setIcon(exportIcon); // 设置图标大小 int iconSize = 28; m_pLoadButton->setIconSize(QSize(iconSize, iconSize)); m_pGenerateButton->setIconSize(QSize(iconSize, iconSize)); m_pDeleteButton->setIconSize(QSize(iconSize, iconSize)); m_pExportButton->setIconSize(QSize(iconSize, iconSize)); int iButtonSize = 32; m_pLoadButton->setFixedSize(iButtonSize, iButtonSize); m_pGenerateButton->setFixedSize(iButtonSize, iButtonSize); m_pDeleteButton->setFixedSize(iButtonSize, iButtonSize); m_pExportButton->setFixedSize(iButtonSize, iButtonSize); // 设置标签文本对齐方式为居中 m_pLoadButtonLabel->setAlignment(Qt::AlignHCenter); m_pGenerateButtonLabel->setAlignment(Qt::AlignHCenter); m_pDeleteButtonLabel->setAlignment(Qt::AlignHCenter); m_pExportButtonLabel->setAlignment(Qt::AlignHCenter); // 使用垂直布局排列按钮和标签 QVBoxLayout *pLoadButtonLayout = new QVBoxLayout(m_pLoadButtonWidget); // 设置尺寸策略,防止布局收缩或拉伸异常 pLoadButtonLayout->setSizeConstraint(QLayout::SetFixedSize); pLoadButtonLayout->addWidget(m_pLoadButton); pLoadButtonLayout->addWidget(m_pLoadButtonLabel); pLoadButtonLayout->setSpacing(0); pLoadButtonLayout->setContentsMargins(0, 0, 0, 0); pLoadButtonLayout->setAlignment(Qt::AlignHCenter); QVBoxLayout *pGenerateButtonLayout = new QVBoxLayout(m_pGenerateButtonWidget); pGenerateButtonLayout->setSizeConstraint(QLayout::SetFixedSize); pGenerateButtonLayout->addWidget(m_pGenerateButton); pGenerateButtonLayout->addWidget(m_pGenerateButtonLabel); pGenerateButtonLayout->setSpacing(0); pGenerateButtonLayout->setContentsMargins(0, 0, 0, 0); pGenerateButtonLayout->setAlignment(Qt::AlignHCenter); QVBoxLayout *pDeleteButtonLayout = new QVBoxLayout(m_pDeleteButtonWidget); pDeleteButtonLayout->setSizeConstraint(QLayout::SetFixedSize); pDeleteButtonLayout->addWidget(m_pDeleteButton); pDeleteButtonLayout->addWidget(m_pDeleteButtonLabel); pDeleteButtonLayout->setSpacing(0); pDeleteButtonLayout->setContentsMargins(0, 0, 0, 0); pDeleteButtonLayout->setAlignment(Qt::AlignHCenter); QVBoxLayout *pExportButtonLayout = new QVBoxLayout(m_pExportButtonWidget); pExportButtonLayout->setSizeConstraint(QLayout::SetFixedSize); pExportButtonLayout->addWidget(m_pExportButton); pExportButtonLayout->addWidget(m_pExportButtonLabel); pExportButtonLayout->setSpacing(0); pExportButtonLayout->setContentsMargins(0, 0, 0, 0); pExportButtonLayout->setAlignment(Qt::AlignHCenter); pButtonLayout->addWidget(m_pLoadButtonWidget); pButtonLayout->addWidget(m_pGenerateButtonWidget); pButtonLayout->addWidget(m_pDeleteButtonWidget); pButtonLayout->addWidget(m_pExportButtonWidget); pButtonLayout->addStretch(); pMainLayout->addLayout(pButtonLayout); // 选项框组 QVBoxLayout *pCheckBoxLayout = new QVBoxLayout(); m_pRedefineKrPcCheckBox = new QCheckBox(tr("Redefine KrPc in natural fissures"), this); m_pUnconsolidationCheckBox = new QCheckBox(tr("Apply unconsolidation in natural fissures"), this); pCheckBoxLayout->addWidget(m_pRedefineKrPcCheckBox); pCheckBoxLayout->addWidget(m_pUnconsolidationCheckBox); pMainLayout->addLayout(pCheckBoxLayout); // 参数树 QHBoxLayout *pTreeWidgetLayout = new QHBoxLayout(); m_pParameterTree = new QTreeWidget(this); m_pParameterTree->setHeaderLabels(QStringList() << tr("Parameters") << ""); m_pParameterTree->setColumnCount(2); // 明确设置列数为2 // 隐藏表头垂直分隔线 QHeaderView* parameterHeader = m_pParameterTree->header(); parameterHeader->setStyleSheet( "QHeaderView {" " background-color: #e5e6e9;" // 表头背景色 "}" "QHeaderView::section {" " border-right: none;" " border-left: none;" "}" ); // 禁止调整列宽 parameterHeader->setResizeMode(QHeaderView::Fixed); // 设置表头不可以拖动 parameterHeader->setMovable(false); parameterHeader->setResizeMode(QHeaderView::Stretch); // 所有列平分 // 设置根节点样式 m_pParameterTree->setStyleSheet( "QTreeWidget::item:has-children {" // 有子节点的项 " background-color: #b2cbeb;" // 浅蓝色背景 "}" ); // 设置整行选中 m_pParameterTree->setSelectionBehavior(QAbstractItemView::SelectRows); m_pParameterTree->setSelectionMode(QAbstractItemView::SingleSelection); setupParameterTree(); pTreeWidgetLayout->addWidget(m_pParameterTree); pMainLayout->addLayout(pTreeWidgetLayout); // 确定/取消按钮 QHBoxLayout *pBottomLayout = new QHBoxLayout(); pBottomLayout->addStretch(); // 添加伸缩项,将按钮推到右侧 m_pOkButton = new QPushButton(tr("OK"), this); m_pCancelButton = new QPushButton(tr("Cancel"), this); pBottomLayout->addWidget(m_pOkButton); pBottomLayout->addWidget(m_pCancelButton); pMainLayout->addLayout(pBottomLayout); } void nmWxDFN::initConnections() { connect(m_pLoadButton, SIGNAL(clicked()), this, SLOT(onLoadButtonClicked())); connect(m_pGenerateButton, SIGNAL(clicked()), this, SLOT(onGenerateButtonClicked())); connect(m_pDeleteButton, SIGNAL(clicked()), this, SLOT(onDeleteButtonClicked())); connect(m_pExportButton, SIGNAL(clicked()), this, SLOT(onExportButtonClicked())); connect(m_pOkButton, SIGNAL(clicked()), this, SLOT(onOkButtonClicked())); connect(m_pCancelButton, SIGNAL(clicked()), this, SLOT(onCancelButtonClicked())); connect(m_pParameterTree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(onItemClicked(QTreeWidgetItem*, int))); } void nmWxDFN::setupParameterTree() { //if (m_vecDFNData.empty()) { // QTreeWidgetItem* pGeneralItem = addRootItem(tr("General")); // addChildItem(pGeneralItem, tr("Number of fissures"), "0", true); //} else { // QTreeWidgetItem* pGeneralItem = addRootItem(tr("General")); // // 添加新的节点 // addChildItem(pGeneralItem, tr("Origin"), tr("Loaded from file"), false); // addChildItem(pGeneralItem, tr("Number of fissures"), QString::number(m_vecDFNData.size()), false); // // 计算总和和平均值 // double totalXf = 0.0; // for (int i = 0; i < m_vecDFNData.size(); i++) { // QVector vecPts = m_vecDFNData[i]->getFracturePoints(); // if (vecPts.size() == 2) { // QPointF ptStartPoint = vecPts[0]; // QPointF ptEndPoint = vecPts[1]; // totalXf += QLineF(ptStartPoint, ptEndPoint).length(); // } // } // double avgXf = m_vecDFNData.empty() ? 0 : totalXf / m_vecDFNData.size(); // addChildItem(pGeneralItem, tr("Total Xf"), QString("%1 m").arg(totalXf)); // addChildItem(pGeneralItem, tr("Average Xf"), QString("%1 m").arg(avgXf)); // QTreeWidgetItem* pGlobalParamsItem = addRootItem(tr("Global fissures physical parameters")); // // 裂缝流动类型 // addChildItem(pGlobalParamsItem, tr("Model type"), m_vecDFNData[0]->getFractureFlowModel().getValue().toString(),false); // // TODO:孔隙度 // addChildItem(pGlobalParamsItem, tr("Porosity"), "0.1", false); // // TODO:裂缝宽度 // addChildItem(pGlobalParamsItem, tr("Width"), QString("%1 m").arg(0.00328084), false); // // TODO:裂缝导流能力 // addChildItem(pGlobalParamsItem, tr("Conductivity"), QString("%1 md.m").arg(m_vecDFNData[0]->getFractureDfc().getValue().toString()), false); //} this->refreshParameterTree(); } void nmWxDFN::refreshParameterTree() { // 禁用UI更新以提高性能 m_pParameterTree->setUpdatesEnabled(false); // 清空现有树结构 m_pParameterTree->clear(); // 根据数据状态选择构建方式 if(!m_vecDFNData.empty()) { setupDFNDataTree(); } else { setupDefaultTree(); } // 重新启用更新 m_pParameterTree->setUpdatesEnabled(true); // 刷新按钮状态 updateButtonsState(); } void nmWxDFN::setupDFNDataTree() { // 1. 添加General分组 QTreeWidgetItem* pGeneralItem = addRootItem(tr("General")); // 填充General分组 //addChildItem(pGeneralItem, tr("Origin"), tr("Loaded from file"), false); QString originText; switch (m_originType) { case Loaded: originText = tr("Loaded from file"); break; case Generated: originText = tr("Generated"); break; default: originText = tr("N/A"); break; } addChildItem(pGeneralItem, tr("Origin"), originText, false); addChildItem(pGeneralItem, tr("Number of fissures"), QString::number(m_vecDFNData.size()), false); // 计算总和和平均值 double totalXf = 0.0; for(int i = 0; i < m_vecDFNData.size(); i++) { QVector vecPts = m_vecDFNData[i]->getFracturePoints(); if(vecPts.size() == 2) { QPointF ptStartPoint = vecPts[0]; QPointF ptEndPoint = vecPts[1]; totalXf += QLineF(ptStartPoint, ptEndPoint).length(); } } double avgXf = m_vecDFNData.empty() ? 0 : totalXf / m_vecDFNData.size(); addChildItem(pGeneralItem, tr("Total Xf"), QString("%1 m").arg(totalXf)); addChildItem(pGeneralItem, tr("Average Xf"), QString("%1 m").arg(avgXf)); // 2. 添加Global参数分组 QTreeWidgetItem* pGlobalParamsItem = addRootItem(tr("Global fissures physical parameters")); // 填充Global参数(添加安全检查) if(!m_vecDFNData.empty()) { // 裂缝流动类型 addChildItem(pGlobalParamsItem, tr("Model type"), m_vecDFNData[0]->getFractureFlowModel().getValue().toString(), false); // TODO:孔隙度 addChildItem(pGlobalParamsItem, tr("Porosity"), "0.1", false); // TODO:裂缝宽度 addChildItem(pGlobalParamsItem, tr("Width"), QString("%1 m").arg(0.00328084), false); // TODO:裂缝导流能力 addChildItem(pGlobalParamsItem, tr("Conductivity"), QString("%1 md.m").arg(m_vecDFNData[0]->getFractureDfc().getValue().toString()), false); } } // 构建默认空树结构 void nmWxDFN::setupDefaultTree() { QTreeWidgetItem* pGeneralItem = addRootItem(tr("General")); addChildItem(pGeneralItem, tr("Number of fissures"), "0", false); } // 槽函数实现 void nmWxDFN::onLoadButtonClicked() { qDebug() << "Load clicked"; nmWxDFNLoadFromFile loadDialog; if(loadDialog.exec() == QDialog::Accepted) { m_originType = Loaded; // 更新数据并刷新界面 m_vecDFNData = nmDataAnalyzeManager::getCurrentInstance()->getDFNFractureDataList(); this->refreshParameterTree(); //// 将导入文件的裂缝信息数据渲染到当前页面 //m_vecDFNData.clear(); //m_vecDFNData = nmDataAnalyzeManager::getCurrentInstance()->getDFNFractureDataList(); //// 查找已存在的节点 //QTreeWidgetItem* pGeneralItem = findItem(tr("General")); //if (pGeneralItem) { // // 删除原来的子节点 // this->deleteAllChildren(pGeneralItem); // // 添加新的节点 // addChildItem(pGeneralItem, tr("Origin"), tr("Loaded from file"), false); // addChildItem(pGeneralItem, tr("Number of fissures"), QString::number(m_vecDFNData.size()), false); // // 计算总和和平均值 // double totalXf = 0.0; // for (int i = 0; i < m_vecDFNData.size(); i++) { // QVector vecPts = m_vecDFNData[i]->getFracturePoints(); // if (vecPts.size() == 2) { // QPointF ptStartPoint = vecPts[0]; // QPointF ptEndPoint = vecPts[1]; // totalXf += QLineF(ptStartPoint, ptEndPoint).length(); // } // } // double avgXf = m_vecDFNData.empty() ? 0 : totalXf / m_vecDFNData.size(); // addChildItem(pGeneralItem, tr("Total Xf"), QString("%1 m").arg(totalXf)); // addChildItem(pGeneralItem, tr("Average Xf"), QString("%1 m").arg(avgXf)); // } //QTreeWidgetItem* pGlobalParamsItem = findItem(tr("Global fissures physical parameters")); //if (pGlobalParamsItem == nullptr) { // // 创建根节点 // pGlobalParamsItem = addRootItem(tr("Global fissures physical parameters")); //} else { // // 删除之前的子节点 // this->deleteAllChildren(pGlobalParamsItem); //} //// 裂缝流动类型 //addChildItem(pGlobalParamsItem, tr("Model type"), m_vecDFNData[0]->getFractureFlowModel().getValue().toString(),false); //// TODO:孔隙度 //addChildItem(pGlobalParamsItem, tr("Porosity"), "0.1", false); //// TODO:裂缝宽度 //addChildItem(pGlobalParamsItem, tr("Width"), QString("%1 m").arg(0.00328084), false); //// TODO:裂缝导流能力 //addChildItem(pGlobalParamsItem, tr("Conductivity"), QString("%1 md.m").arg(m_vecDFNData[0]->getFractureDfc().getValue().toString()), false); } } void nmWxDFN::updateButtonsState() { bool hasData = !m_vecDFNData.empty(); // Load 和Generate 按钮始终可用 m_pLoadButton->setEnabled(true); m_pGenerateButton->setEnabled(true); // 其余按钮只有在有数据时才可用 m_pDeleteButton->setEnabled(hasData); m_pExportButton->setEnabled(hasData); } void nmWxDFN::onGenerateButtonClicked() { nmDataAnalyzeManager* mgr = nmDataAnalyzeManager::getCurrentInstance(); nmGuiPlot* plot = mgr->getPlot(); nmDataOutline* outline = mgr->getOutlineData(); nmWxDFNGenerateDlg dlg(this, plot, outline); if(dlg.exec() == QDialog::Accepted) { m_originType = Generated; m_vecDFNData = mgr->getDFNFractureDataList(); refreshParameterTree(); } } void nmWxDFN::onDeleteButtonClicked() { qDebug() << "Delete clicked"; // 清空原来的DFN图元数据 if(!nmDataAnalyzeManager::getCurrentInstance()->getDFNFractureDataList().isEmpty()) { nmGuiPlot* pCurPlot = nmDataAnalyzeManager::getCurrentInstance()->getPlot(); pCurPlot->deleteAllDFNPlots(); // m_pParameterTree->clear(); m_originType = None; // 更新数据并刷新界面 m_vecDFNData = nmDataAnalyzeManager::getCurrentInstance()->getDFNFractureDataList(); this->refreshParameterTree(); } } void nmWxDFN::onExportButtonClicked() { nmWxDFNExportDlg dlg(this); dlg.exec(); } void nmWxDFN::onOkButtonClicked() { //qDebug() << "Ok clicked"; this->accept(); } void nmWxDFN::onCancelButtonClicked() { //qDebug() << "Cancel clicked"; this->reject(); } void nmWxDFN::onItemClicked(QTreeWidgetItem* item, int column) { if(item->text(0) == "Number of fissures") { // 设置第二列获得焦点 m_pParameterTree->editItem(item, 1); } } QTreeWidgetItem* nmWxDFN::addRootItem(const QString& name, bool expand) { QTreeWidgetItem* item = new QTreeWidgetItem(m_pParameterTree); item->setText(0, name); item->setFlags(item->flags() & ~Qt::ItemIsSelectable); // 分组标题不可选 item->setExpanded(expand); return item; } QTreeWidgetItem* nmWxDFN::addChildItem(QTreeWidgetItem* parent, const QString& name, const QString& value, bool editable) { if(!parent) return nullptr; QTreeWidgetItem* item = new QTreeWidgetItem(parent); item->setText(0, name); item->setText(1, value); Qt::ItemFlags flags = item->flags(); if(editable) { flags |= Qt::ItemIsEditable | Qt::ItemIsSelectable; } else { flags |= Qt::ItemIsSelectable; } item->setFlags(flags); return item; } QTreeWidgetItem* nmWxDFN::findItem(const QString& name, QTreeWidgetItem* parent) const { QTreeWidgetItemIterator it(parent ? parent : m_pParameterTree->invisibleRootItem()); while(*it) { if((*it)->text(0) == name) { return *it; } ++it; } return nullptr; } void nmWxDFN::deleteAllChildren(QTreeWidgetItem* parent) { if(!parent) return; // 逆向删除避免索引问题 for(int i = parent->childCount() - 1; i >= 0; --i) { delete parent->takeChild(i); } }