fix(nmNum): 修复分析计算基准与界面状态

- 成功求解后在内存中保留完整输入,分析复制该输入并仅替换采样参数,避免使用未求解的编辑值。
- 主井、历史曲线、基准曲线及气井拟压力转换均使用同次求解的数据,失败或取消时保留旧基准。
- 未生成模型时禁用分析按钮,将 Results 窗口及表格背景统一为白色。
- 本次不增加输入快照的文件保存与加载。
feature/Sensitivity-20261012
lvjunjie 1 week ago
parent 4fb38c3022
commit ed50f2c1d0

@ -36,12 +36,14 @@ class NMCALCULATION_EXPORT nmCalculationDllPebiSolverTask : public QThread {
* @param sAutoFitTargetWellName 自动拟合目标井名;空值表示完整成果计算。
* @param parent Qt 父对象。
* @param bDeferManualSnapshot 手工求解是否由界面事件循环分批捕获输入。
* @param bUseSolvedInput 敏感性分析只恢复最后成功模型的输入,不捕获当前编辑值。
*/
nmCalculationDllPebiSolverTask(QString sPostprocessingDir,
nmDataAnalyzeManager* pDataManager = nullptr,
const QString& sAutoFitTargetWellName = QString(),
QObject *parent = nullptr,
bool bDeferManualSnapshot = false);
bool bDeferManualSnapshot = false,
bool bUseSolvedInput = false);
~nmCalculationDllPebiSolverTask();
/** @brief QThread 入口,执行单次或敏感性批量求解并发送一次完成信号。 */
@ -146,6 +148,8 @@ class NMCALCULATION_EXPORT nmCalculationDllPebiSolverTask : public QThread {
void discardPendingFullResult();
/** @brief 同步路径在任务创建线程一次性捕获全部求解输入。 */
bool captureInputSnapshot(const QString& sAutoFitTargetWellName);
/** @brief 从所属分析的最后成功结果恢复完整输入。 */
bool restoreSolvedInput();
/** @brief 手工求解在线程内完成场景、缓存和 VTK 基础网格准备。 */
bool prepareManualInput();
/** @brief 无锁读取原子停止标记。 */

@ -19,6 +19,7 @@ class vtkUnstructuredGrid;
class nmPebiResultSnapshotBuilder;
class nmPebiResultSnapshotRenderAdapter;
class nmPebiResultSnapshotSerializer;
struct nmPebiSolverInputSnapshot;
/** @brief 一条求解器槽位在最后成功结果中的冻结描述。 */
struct NM_DATA_EXPORT nmPebiResultSolverSlot
@ -314,6 +315,10 @@ public:
const nmPebiResultPvtParameters& getPvtParameters() const;
/** @brief 返回求解时冻结的求解设置。 */
const nmPebiResultSolverSettings& getSolverSettings() const;
/** @brief 最后成功模型的只读输入,仅在本次运行中保留,不参与文件保存。 */
const QSharedPointer<const nmPebiSolverInputSnapshot>& getSensitivityInput() const;
/** @brief 返回与完整输入对应的主井编码。 */
const QString& getSensitivityWellCode() const;
private:
struct PressureFrame
@ -391,6 +396,9 @@ private:
nmPebiResultPvtParameters m_oPvtParameters;
/** @brief 求解时冻结的求解设置。 */
nmPebiResultSolverSettings m_oSolverSettings;
/** @brief 输入随成功结果一起发布,敏感性任务只使用其独立副本。 */
QSharedPointer<const nmPebiSolverInputSnapshot> m_sensitivityInput;
QString m_sensitivityWellCode;
// 只有 Builder 和快照序列化器可以在发布前填充私有数据。
friend class nmPebiResultSnapshotBuilder;

@ -58,6 +58,9 @@ public:
bool setPvtParameters(const nmPebiResultPvtParameters& oParameters);
/** @brief 设置求解时冻结的网格、时间步和求解器配置。 */
bool setSolverSettings(const nmPebiResultSolverSettings& oSettings);
/** @brief 将当次实际输入附在结果候选上,仅成功提交后成为分析基准。 */
bool setSensitivityInput(const QSharedPointer<const nmPebiSolverInputSnapshot>& input,
const QString& wellCode);
/** @brief 完成全部结构校验并封闭候选,失败后该 Builder 不可继续使用。 */
bool finalize(QString* pError = NULL);

@ -90,6 +90,7 @@ private slots:
void onAutomaticFittingClicked();
void onForecastClicked();
void onSensitiveClicked();
void updateSensitiveButtonEnabled();
// 现有和调整的槽函数
void onOptionsIconClicked(); // "包含其他井"按钮点击

@ -92,6 +92,7 @@ struct nmPebiSolverInputSnapshot
}
nmPebiGridInputSnapshot m_oGridInput; ///< 网格、场景、井顺序和授权路径值快照。
QString m_sPrimaryWellCode; ///< 当次成功模型对应的分析主井。
nmPebiGridResult m_oGridResult; ///< 已有网格副本或后台新生成的局部网格。
/** @brief 在 DataManager 线程冻结的静态属性参考值、插值数据和授权路径。 */
nmPebiStaticPropertyCalculationInput m_oStaticPropertyInput;
@ -210,6 +211,28 @@ bool isFiniteSolverNumber(double value)
#endif
}
bool savedPseudoPressure(const nmDataBinaryTools::NM_PEBI_SCENE& scene,
double pressure, double& result)
{
// 气井分析使用求解时的拟压力表,避免当前编辑改写全局转换器配置。
const std::vector<double>& p = scene.PVT.pseudoPressureP;
const std::vector<double>& ps = scene.PVT.pseudoPressurePs;
if(p.size() < 2 || p.size() != ps.size() || !isFiniteSolverNumber(pressure)) return false;
const bool ascending = p[1] > p[0];
size_t first = 0, last = p.size();
while(first < last) {
const size_t mid = first + (last - first) / 2;
if(ascending ? p[mid] < pressure : p[mid] > pressure) first = mid + 1;
else last = mid;
}
const size_t right = (std::max)(size_t(1), (std::min)(first, p.size() - 1));
const double span = p[right] - p[right - 1];
if(span == 0.0) return false;
// 与现有离线计算一致,区间内线性插值,超出范围沿端点外推。
result = ps[right - 1] + (pressure - p[right - 1]) / span * (ps[right] - ps[right - 1]);
return isFiniteSolverNumber(result);
}
// 旧的双对数曲线 DLL 仍是单相接口,只在结果后处理时取输入捕获阶段
// 冻结的制度参考相。PEBI 主求解仍在场景中接收油、气、水三相全部流量。
const QVector<double>* referenceRatesOf(
@ -382,6 +405,7 @@ bool captureResultParameters(
nmPebiResultPvtParameters& oPvt =
oSnapshot.m_oResultPvtParameters;
oSnapshot.m_sPrimaryWellCode = pDataManager->getPrimaryWellCode();
oPvt.m_dConstantBo = pReservoir->getBo().getValue().toDouble();
oPvt.m_dConstantMiuo = pReservoir->getMiuo().getValue().toDouble();
oPvt.m_dConstantBg = pReservoir->getBg().getValue().toDouble();
@ -634,7 +658,8 @@ nmCalculationDllPebiSolverTask::nmCalculationDllPebiSolverTask(
nmDataAnalyzeManager* pDataManager,
const QString& sAutoFitTargetWellName,
QObject *parent,
bool bDeferManualSnapshot):
bool bDeferManualSnapshot,
bool bUseSolvedInput):
QThread(parent),
m_sPostprocessingDir(sPostprocessingDir),
m_pDataManager(pDataManager != nullptr
@ -665,7 +690,9 @@ nmCalculationDllPebiSolverTask::nmCalculationDllPebiSolverTask(
m_bManagerUseActive = true;
}
if(bDeferManualSnapshot && sAutoFitTargetWellName.isEmpty()) {
if(bUseSolvedInput) {
m_bInputSnapshotValid = restoreSolvedInput();
} else if(bDeferManualSnapshot && sAutoFitTargetWellName.isEmpty()) {
// 手工求解由界面事件循环分批冻结值输入;start() 必须等状态释放后再调用。
m_pManualCaptureState = new nmPebiManualCaptureState();
} else {
@ -916,12 +943,15 @@ nmCalculationDllPebiSolverTask* nmCalculationDllPebiSolverTask::createSensitivit
task->m_pSensitivityResult->m_variables = frozenSampling.getVariables();
task->m_pSensitivityResult->m_sWellCode = task->m_sAutoFitTargetWellCode;
if(m_pDataManager != nullptr) {
nmDataWellBase* well = m_pDataManager->findWellByCode(task->m_sAutoFitTargetWellCode);
if(well != nullptr) {
task->m_pSensitivityResult->m_sWellName = well->getWellName();
task->m_pSensitivityResult->m_vecHistoryLogLog = well->getHistoryLogLog();
// 复用原模型已有数值解作为对比基准,不增加一次求解或跟随后续结果变化。
task->m_pSensitivityResult->m_vecBaseLogLog = well->getResultLogLog();
const QSharedPointer<const nmPebiResultSnapshot> solved = m_pDataManager->getPebiResultSnapshot();
for(int i = 0; !solved.isNull() && i < solved->getWellCount(); ++i) {
const nmPebiResultWellSnapshot* well = solved->getWellAt(i);
if(well->m_sWellCode != task->m_sAutoFitTargetWellCode) continue;
// 历史和基准曲线必须与计算输入属于同一次求解。
task->m_pSensitivityResult->m_sWellName = well->m_sWellName;
task->m_pSensitivityResult->m_vecHistoryLogLog = well->m_oCurves.m_vecHistoryLogLog;
task->m_pSensitivityResult->m_vecBaseLogLog = well->m_oCurves.m_vecResultLogLog;
break;
}
}
return task.take();
@ -1346,6 +1376,20 @@ void nmCalculationDllPebiSolverTask::releaseDataManagerUse()
}
}
bool nmCalculationDllPebiSolverTask::restoreSolvedInput()
{
// 复制最后成功求解的输入,不再从当前编辑模型重新捕获。
if(!m_pDataManager || QThread::currentThread() != m_pDataManager->thread()) return false;
const QSharedPointer<const nmPebiResultSnapshot> solved = m_pDataManager->getPebiResultSnapshot();
if(solved.isNull() || solved->getSensitivityInput().isNull())
return fail(tr("Regenerate the model before running sensitivity."));
*m_pInputSnapshot = *solved->getSensitivityInput();
m_nGridInputRevision = solved->getGridInputRevision();
m_nResultInputRevision = solved->getResultInputRevision();
m_sAutoFitTargetWellCode = m_pInputSnapshot->m_sPrimaryWellCode;
return true;
}
bool nmCalculationDllPebiSolverTask::captureInputSnapshot(
const QString& sAutoFitTargetWellName)
{
@ -1869,11 +1913,13 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
// p1.pw 是求解器返回的原始井底压力, 后续仍按 MPa 保存到 vvecPressure.
// 只有气单相变化 PVT 模型的双对数和半对数计算需要改用拟压力.
const bool usePseudoPressure = (modelType == static_cast<int>(SMT_Gas_VariablePvt));
CalPseudoPressure calPseudoPressure = usePseudoPressure
const bool useSavedPseudoPressure = usePseudoPressure &&
m_pInputSnapshot->m_oSensitivityBaseline.m_nTarget >= 0;
CalPseudoPressure calPseudoPressure = usePseudoPressure && !useSavedPseudoPressure
? getPseudoPressureConverter()
: nullptr;
if(usePseudoPressure && calPseudoPressure == nullptr) {
if(usePseudoPressure && !useSavedPseudoPressure && calPseudoPressure == nullptr) {
qWarning() << "Failed to load the gas pseudo-pressure converter.";
return fail(tr("Failed to load the gas pseudo-pressure converter."));
}
@ -2011,8 +2057,11 @@ bool nmCalculationDllPebiSolverTask::buildPebiModeResult(
double pressureForLog = p1.pw[wellIdx][i];
if(usePseudoPressure
&& (!isFiniteSolverNumber(pressureForLog)
// -1 与主界面调用一致, 表示使用 configPsAbouts() 配置的当前模式.
|| !calPseudoPressure(pressureForLog, pressureForLog, -1)
// 敏感性任务只查求解时保存的表,不能读取已被编辑或其他窗口改写的全局配置。
|| !(useSavedPseudoPressure
? savedPseudoPressure(
m_pInputSnapshot->m_oGridInput.m_oScene, pressureForLog, pressureForLog)
: calPseudoPressure(pressureForLog, pressureForLog, -1))
|| !isFiniteSolverNumber(pressureForLog))) {
qWarning() << "Failed to convert gas pressure to pseudo-pressure:"
<< p1.pw[wellIdx][i]
@ -2261,6 +2310,17 @@ bool nmCalculationDllPebiSolverTask::buildPebiResultSnapshotCandidate(
try {
nmPebiResultSnapshotBuilder oBuilder;
// 复用现有输入结构,在转移井制度和曲线前留一份只读副本,随成功结果发布。
QSharedPointer<nmPebiSolverInputSnapshot> sensitivityInput(
new nmPebiSolverInputSnapshot(*m_pInputSnapshot));
sensitivityInput->m_bAutoFitTargetOnly = true;
sensitivityInput->m_bRequiresGridCalculation = false;
sensitivityInput->m_bGridResultNeedsCommit = false;
// 分析只需要 DLL 网格值,不保留正式结果的 VTK 可写引用。
sensitivityInput->m_pBaseGrid = NULL;
sensitivityInput->m_pSourceBaseGrid = NULL;
sensitivityInput->m_oGridResult.m_pUnstructuredGrid = NULL;
if(!oBuilder.setSensitivityInput(sensitivityInput, m_pInputSnapshot->m_sPrimaryWellCode)) return false;
if(!oBuilder.setInputRevisions(m_nGridInputRevision,
m_nResultInputRevision)) {
return false;

@ -12,6 +12,18 @@
#include <QUuid>
const QSharedPointer<const nmPebiSolverInputSnapshot>& nmPebiResultSnapshot::getSensitivityInput() const
{
// 管理器仅持有只读输入,复制和采样由求解模块完成。
return m_sensitivityInput;
}
const QString& nmPebiResultSnapshot::getSensitivityWellCode() const
{
// 界面定位求解时的井,不能因编辑主井而改变参数基准。
return m_sensitivityWellCode;
}
namespace {
bool deepCopyNamedArray(vtkFieldData* pSource,

@ -885,6 +885,17 @@ bool nmPebiResultSnapshotBuilder::setSolverSettings(
return true;
}
bool nmPebiResultSnapshotBuilder::setSensitivityInput(
const QSharedPointer<const nmPebiSolverInputSnapshot>& input, const QString& wellCode)
{
// 与结果候选一起发布,求解失败或取消不会替换上次输入。
if(!canWrite()) return false;
if(input.isNull() || wellCode.isEmpty()) return fail("PEBI sensitivity input is incomplete.");
m_pCandidate->m_sensitivityInput = input;
m_pCandidate->m_sensitivityWellCode = wellCode;
return true;
}
bool nmPebiResultSnapshotBuilder::validate(QString* pError)
{
// 第一部分校验快照身份、输入版本和所有必填结果载荷。

@ -807,6 +807,7 @@ void nmWxNumericalDesign::initButton()
// 创建敏感性分析按钮
m_pSensitiveBtn = new QPushButton(tr("Sensitive"), this);
m_pSensitiveBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
updateSensitiveButtonEnabled();
// 创建右下角按钮
m_pGenerateButton = new QPushButton(tr("Generate"), this); // "生成"按钮
m_pGenerateButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); // 固定尺寸
@ -842,6 +843,8 @@ void nmWxNumericalDesign::setupConnections()
this, SLOT(onIncludeOtherWellsToggled(bool)));
// Map井增删或产量、压力目标变化后,立即更新多井选项是否可用。
if(m_pDataManager != nullptr) {
connect(m_pDataManager, SIGNAL(sigPebiResultSnapshotChanged()),
this, SLOT(updateSensitiveButtonEnabled()), Qt::UniqueConnection);
connect(m_pDataManager, SIGNAL(dataChanged()),
this, SLOT(onWellCollectionChanged()), Qt::UniqueConnection);
// createWell() 会在井对象登记时先发送 dataChanged(),此时 WellCode、
@ -1442,8 +1445,21 @@ void nmWxNumericalDesign::onForecastClicked()
dlg->show();
}
void nmWxNumericalDesign::updateSensitiveButtonEnabled()
{
// 只有本次运行中成功求解过才有完整输入,编辑参数不会改变已有分析基准。
const QSharedPointer<const nmPebiResultSnapshot> solved = m_pDataManager
? m_pDataManager->getPebiResultSnapshot() : QSharedPointer<const nmPebiResultSnapshot>();
const bool available = !solved.isNull() && !solved->getSensitivityInput().isNull();
m_pSensitiveBtn->setEnabled(available);
m_pSensitiveBtn->setToolTip(available ? QString() : tr("Generate the model to enable sensitivity analysis."));
}
void nmWxNumericalDesign::onSensitiveClicked()
{
// 没有模型时直接阻止进入,正常交互由按钮置灰表达,不再等生成分析时弹框。
updateSensitiveButtonEnabled();
if(!m_pSensitiveBtn->isEnabled()) return;
nmWxSensitive* dlg = new nmWxSensitive(this, m_pDataManager);
// 按数值生成按钮的现有路径,将任务请求转发给所属主窗口。
connect(dlg, SIGNAL(sigSensitivityTaskReady(nmWxSensitive*,nmCalculationDllPebiSolverTask*)),

@ -7,8 +7,6 @@
#include "nmDataPerforation.h"
#include "nmPebiResultSnapshot.h"
#include "nmCalculationDllPebiSolverTask.h"
#include "iSubWndFitting.h"
#include "mGui/mGuiAnal/iAnalRun.h"
#include "iUnitHelper.h"
#include "iUnitGroup.h"
#include "iSysParaHelper.h"
@ -62,8 +60,6 @@
#include <QScopedPointer>
#include <new>
#pragma comment(lib, "mGuiAnal.lib")
#include <math.h>
#include <float.h>
#include <limits.h>
@ -656,11 +652,16 @@ void nmWxSensitive::refreshModelValues()
? m_pDataManager->getPebiResultSnapshot() : QSharedPointer<const nmPebiResultSnapshot>();
const bool resetRanges = !snapshot.isNull() &&
snapshot->getSnapshotId() != m_sensitiveData.getModelSnapshotId();
nmDataWellBase* well = m_pDataManager
? m_pDataManager->findWellByCode(m_pDataManager->getPrimaryWellCode()) : nullptr;
const QString wellCode = !snapshot.isNull() ? snapshot->getSensitivityWellCode() : QString();
nmDataWellBase* well = m_pDataManager ? m_pDataManager->findWellByCode(wellCode) : nullptr;
nmDataReservoir* reservoir = m_pDataManager ? m_pDataManager->getReservoirData() : nullptr;
const nmPebiResultWellSnapshot* solvedWell = !snapshot.isNull() && well
? snapshot->findWell(well->getWellInstanceId()) : nullptr;
const nmPebiResultWellSnapshot* solvedWell = nullptr;
for(int i = 0; !snapshot.isNull() && i < snapshot->getWellCount(); ++i) {
if(snapshot->getWellAt(i)->m_sWellCode == wellCode) {
solvedWell = snapshot->getWellAt(i);
break;
}
}
const QStringList names = QStringList() << "Skin" << "C" << "Pi" << "k" << "h" << QString(QChar(0x03c6));
for (int n = 0; n < names.size(); ++n) {
nmDataAttribute* attribute = nullptr;
@ -688,8 +689,10 @@ void nmWxSensitive::refreshModelValues()
nmDataSensitive::VariableSampling& variable = m_sensitiveData.getVariable(index);
// 在局部属性上替换数值,不能把未求解的编辑值带入 Model value 或默认范围。
nmDataAttribute solvedAttribute;
if (attribute && !snapshot.isNull()) {
solvedAttribute = *attribute;
if (!snapshot.isNull()) {
if (attribute) solvedAttribute = *attribute;
else solvedAttribute.setUnit(samplingBaseUnit(name));
attribute = &solvedAttribute;
const nmPebiResultReservoirParameters& solvedReservoir = snapshot->getReservoirParameters();
if (name == "Skin" || name == "C") {
if (!solvedWell || (name == "Skin" && !solvedWell->m_bHasSkin)) attribute = nullptr;
@ -698,7 +701,6 @@ void nmWxSensitive::refreshModelValues()
else if (name == "k") solvedAttribute.setValue(solvedReservoir.m_dPermeability);
else if (name == "h") solvedAttribute.setValue(solvedReservoir.m_dThickness);
else if (name == QString(QChar(0x03c6))) solvedAttribute.setValue(solvedReservoir.m_dPorosity);
if (attribute) attribute = &solvedAttribute;
}
double physicalMin = 0.0, physicalMax = 0.0;
if (!attribute || !samplingPhysicalRange(name, physicalMin, physicalMax)) {
@ -954,20 +956,6 @@ bool nmWxSensitive::saveDataFromUI()
detailStack->setCurrentIndex(idx + 1);
return false;
}
if (!variable.getEnabled()) continue;
// 本期处理常量参数;属性场开启时常量会被插值覆盖,因此不能静默运行。
if (m_pDataManager && (name == "k" || name == "h" || name == QString(QChar(0x03c6)))) {
const QString property = name == QString(QChar(0x03c6)) ? "phi" : name;
const QVector<nmPropertyInterpolationDataSet> dataSets = m_pDataManager->getPropertyInterpolationDataSets();
for (int field = 0; field < dataSets.size(); ++field) {
if (dataSets[field].useForCalculation && dataSets[field].property == property &&
!dataSets[field].points.isEmpty()) {
QMessageBox::warning(this, tr("Sensitivity"),
tr("%1 uses a non-uniform field. Disable that field before sampling a constant value.").arg(name));
return false;
}
}
}
}
m_sensitiveData = candidate;
return true;
@ -1597,34 +1585,11 @@ void nmWxSensitive::onTreeItemChanged(QTreeWidgetItem* item, int column)
void nmWxSensitive::onGenerateClicked()
{
if(m_calculationRunning || !m_pDataManager || !saveDataFromUI()) return;
nmDataWellBase* well = m_pDataManager->findWellByCode(m_pDataManager->getPrimaryWellCode());
if(!well || well->getWellName().isEmpty()) {
QMessageBox::warning(this, tr("Sensitivity"), tr("The target well is unavailable."));
return;
}
// 气井转换器使用本窗口所属分析的配置,不能随当前活动窗口切换。
if(m_pDataManager->getSolverModelType() == SMT_Gas_VariablePvt) {
iSubWndFitting* fitting = nullptr;
QMap<iSubWndFitting*, nmDataAnalyzeManager*>::const_iterator it =
nmDataAnalyzeManager::s_mapDataAnalManager.constBegin();
for(; it != nmDataAnalyzeManager::s_mapDataAnalManager.constEnd(); ++it) {
if(it.value() == m_pDataManager) { fitting = it.key(); break; }
}
iAnalRun* analRun = fitting ? fitting->getAnalRun() : nullptr;
if(!analRun || !analRun->configPsAbouts(true, fitting->getModelOption(),
false, fitting->getAllWxPtr())) {
QMessageBox::warning(this, tr("Sensitivity"),
tr("Gas pseudo-pressure data is unavailable or invalid."));
return;
}
}
QString error;
QScopedPointer<nmCalculationDllPebiSolverTask> task;
try {
// 在管理器所属的界面线程捕获基准并复制一次,后台任务不持有管理器。
nmCalculationDllPebiSolverTask source(QString(), m_pDataManager, well->getWellName());
// 从最后成功结果恢复完整输入,当前编辑参数和全局拟压力配置不参与本次分析。
nmCalculationDllPebiSolverTask source(QString(), m_pDataManager, QString(), nullptr, false, true);
task.reset(source.createSensitivityBatch(m_sensitiveData, &error));
} catch(const std::bad_alloc&) {
error = tr("Insufficient memory to prepare solver input.");
@ -1721,12 +1686,14 @@ void nmWxSensitive::onResultsClicked()
if(!resultsButton->isEnabled()) return;
emit sigSensitiveResultsRequested();
if(m_resultsDialog.isNull()) {
m_resultsDialog = new QDialog(this);
// 与参数窗口共用框架对话框样式,避免普通 QDialog 使用默认灰色背景。
m_resultsDialog = new iDlgBase(this);
m_resultsDialog->setAttribute(Qt::WA_DeleteOnClose);
m_resultsDialog->setWindowTitle(tr("Sensitivity Results"));
m_resultsDialog->resize(700, 380);
QVBoxLayout* layout = new QVBoxLayout(m_resultsDialog.data());
QTableView* table = new QTableView(m_resultsDialog.data());
table->setStyleSheet("QTableView { background-color: white; }");
m_resultsModel = new SensitivityResultsModel(m_resultsDialog.data());
m_resultsModel->setResults(m_pDataManager->getSensitiveData()->getResults());
table->setModel(m_resultsModel.data());

Loading…
Cancel
Save