2025-12-11T16:15:35
This commit is contained in:
parent
8e3c534710
commit
0583d5f84f
26
.vscode/settings.json
vendored
Normal file
26
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"cmake.sourceDirectory": "D:/gitfile/analysis_tool/src",
|
||||
"files.associations": {
|
||||
"new": "cpp",
|
||||
"__locale": "cpp",
|
||||
"ios": "cpp",
|
||||
"queue": "cpp",
|
||||
"stack": "cpp",
|
||||
"__config": "cpp",
|
||||
"__bit_reference": "cpp",
|
||||
"__hash_table": "cpp",
|
||||
"__split_buffer": "cpp",
|
||||
"__tree": "cpp",
|
||||
"array": "cpp",
|
||||
"deque": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"list": "cpp",
|
||||
"map": "cpp",
|
||||
"set": "cpp",
|
||||
"string": "cpp",
|
||||
"string_view": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"vector": "cpp"
|
||||
}
|
||||
}
|
||||
5
DSCAnalysisTool-release/bin/log/20251201.log
Normal file
5
DSCAnalysisTool-release/bin/log/20251201.log
Normal file
@ -0,0 +1,5 @@
|
||||
[2025-12-01 10:46:10,897] main...
|
||||
[2025-12-01 10:46:10,899] config file existed.
|
||||
[2025-12-01 10:46:10,936] version:1.3.5.1
|
||||
[2025-12-01 10:46:10,980] setEventHandlerEnable...0
|
||||
[2025-12-01 10:46:31,805] serialport destructor.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2
src/.vscode/launch.json
vendored
2
src/.vscode/launch.json
vendored
@ -18,7 +18,7 @@
|
||||
],
|
||||
"externalConsole": false,
|
||||
"miDebuggerPath": "D:/qt/Qt5.14.2/5.14.2/mingw73_64/bin/gdb.exe",
|
||||
"visualizerFile": "c:\\Users\\sunqu\\AppData\\Roaming\\Code\\User\\workspaceStorage\\7f93734217a2e383fe34beaf49d497fe\\tonka3000.qtvsctools\\qt.natvis.xml"
|
||||
"visualizerFile": "c:\\Users\\sunqu\\AppData\\Roaming\\Trae CN\\User\\workspaceStorage\\7f93734217a2e383fe34beaf49d497fe\\tonka3000.qtvsctools\\qt.natvis.xml"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -9,7 +9,7 @@ CONFIG+=precompile_header
|
||||
PRECOMPILED_HEADER=stable.h
|
||||
|
||||
#
|
||||
VERSION = 1.3.7
|
||||
VERSION = 1.4.0
|
||||
# 设置目标文件名,包含版本号
|
||||
TARGET = DSCAnalysisTool_$${VERSION}
|
||||
|
||||
|
||||
154
src/global.cpp
154
src/global.cpp
@ -3,23 +3,24 @@
|
||||
|
||||
#include "global.h"
|
||||
|
||||
namespace Global {
|
||||
namespace Global
|
||||
{
|
||||
Mode _mode = Mode::Analysis;
|
||||
|
||||
AxisMode _axisMode = AxisMode::SingleY;
|
||||
|
||||
QVector<CurveFileData> _curveFileDataVtr;
|
||||
|
||||
int _currentPhase = 0;
|
||||
ExperimentInfo _experimentInfo;
|
||||
int _currentPhase = 0;
|
||||
ExperimentInfo _experimentInfo;
|
||||
QVector<CurveExperimentData> _curveExperimentDataVtr;
|
||||
CurveExperimentData *_currentCurveExperimentDataPtr = nullptr;
|
||||
CurveExperimentData *_currentCurveExperimentDataPtr = nullptr;
|
||||
|
||||
bool _smoothnessFlag = false;
|
||||
bool _smoothnessFlag = false;
|
||||
QVector<CurveExperimentData> _curveSmoothnessDataVtr;
|
||||
QString _smoothnessFileName;
|
||||
QString _smoothnessFileName;
|
||||
|
||||
bool _enthalpyCoefficientEnableFlag = false;
|
||||
bool _enthalpyCoefficientEnableFlag = false;
|
||||
QVector<double> _enthalpyCoefficientVtr;
|
||||
|
||||
bool _displayTimeValue = false;
|
||||
@ -29,18 +30,21 @@ namespace Global {
|
||||
bool _experimentOITFlag = false;
|
||||
|
||||
// OIT auto mode.
|
||||
bool _OITAutoAnalysisModeFlag = false;
|
||||
bool _OITAutoAnalysisModeFlag = false;
|
||||
double _OITAutoAnalysisCoefficient = OITAutoAnalysisDefaultCoefficient;
|
||||
double _OITAutoAnalysisThreshold = OITAutoAnalysisDefaultThreshold;
|
||||
double _OITAutoAnalysisThreshold = OITAutoAnalysisDefaultThreshold;
|
||||
// 实验文件
|
||||
QStringList _fileList;
|
||||
|
||||
QString converDoubleToStr(const double num) {
|
||||
QString converDoubleToStr(const double num)
|
||||
{
|
||||
return QString::number(num, 'f', 3);
|
||||
}
|
||||
|
||||
void quadraticLeastSquaresFit(double x[], double y[], int n, double coeff[]) {
|
||||
if (n < 3) {
|
||||
void quadraticLeastSquaresFit(double x[], double y[], int n, double coeff[])
|
||||
{
|
||||
if (n < 3)
|
||||
{
|
||||
throw std::invalid_argument("At least 3 data points are required for quadratic fitting");
|
||||
}
|
||||
|
||||
@ -48,12 +52,13 @@ namespace Global {
|
||||
double sum_y = 0, sum_xy = 0, sum_x2y = 0;
|
||||
|
||||
// 计算各项累加和
|
||||
for (int i = 0; i < n; ++i) {
|
||||
double xi = x[i];
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
double xi = x[i];
|
||||
double xi2 = xi * xi;
|
||||
double xi3 = xi2 * xi;
|
||||
double xi4 = xi3 * xi;
|
||||
double yi = y[i];
|
||||
double yi = y[i];
|
||||
|
||||
sum_x += xi;
|
||||
sum_x2 += xi2;
|
||||
@ -66,50 +71,61 @@ namespace Global {
|
||||
|
||||
// 构建正规方程组的增广矩阵
|
||||
double matrix[3][4] = {
|
||||
{ sum_x4, sum_x3, sum_x2, sum_x2y }, // 对应方程: a*Σx⁴ + b*Σx³ + c*Σx² = Σx²y
|
||||
{ sum_x3, sum_x2, sum_x, sum_xy }, // 对应方程: a*Σx³ + b*Σx² + c*Σx = Σxy
|
||||
{ sum_x2, sum_x, static_cast<double>(n), sum_y } // 对应方程: a*Σx² + b*Σx + c*n = Σy
|
||||
{sum_x4, sum_x3, sum_x2, sum_x2y}, // 对应方程: a*Σx⁴ + b*Σx³ + c*Σx² = Σx²y
|
||||
{sum_x3, sum_x2, sum_x, sum_xy}, // 对应方程: a*Σx³ + b*Σx² + c*Σx = Σxy
|
||||
{sum_x2, sum_x, static_cast<double>(n), sum_y} // 对应方程: a*Σx² + b*Σx + c*n = Σy
|
||||
};
|
||||
|
||||
// 高斯消元法解方程组
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
// 部分主元选择
|
||||
int maxRow = i;
|
||||
for (int k = i + 1; k < 3; ++k) {
|
||||
if (std::abs(matrix[k][i]) > std::abs(matrix[maxRow][i])) {
|
||||
for (int k = i + 1; k < 3; ++k)
|
||||
{
|
||||
if (std::abs(matrix[k][i]) > std::abs(matrix[maxRow][i]))
|
||||
{
|
||||
maxRow = k;
|
||||
}
|
||||
}
|
||||
|
||||
// 交换行
|
||||
for (int k = i; k < 4; ++k) {
|
||||
for (int k = i; k < 4; ++k)
|
||||
{
|
||||
std::swap(matrix[i][k], matrix[maxRow][k]);
|
||||
}
|
||||
|
||||
// 消元
|
||||
for (int k = i + 1; k < 3; ++k) {
|
||||
for (int k = i + 1; k < 3; ++k)
|
||||
{
|
||||
double factor = matrix[k][i] / matrix[i][i];
|
||||
for (int j = i; j < 4; ++j) {
|
||||
for (int j = i; j < 4; ++j)
|
||||
{
|
||||
matrix[k][j] -= factor * matrix[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 回代求解
|
||||
coeff[2] = matrix[2][3] / matrix[2][2]; // c
|
||||
coeff[1] = (matrix[1][3] - matrix[1][2] * coeff[2]) / matrix[1][1]; // b
|
||||
coeff[0] = (matrix[0][3] - matrix[0][2] * coeff[2] - matrix[0][1] * coeff[1]) / matrix[0][0]; // a
|
||||
coeff[2] = matrix[2][3] / matrix[2][2]; // c
|
||||
coeff[1] = (matrix[1][3] - matrix[1][2] * coeff[2]) / matrix[1][1]; // b
|
||||
coeff[0] = (matrix[0][3] - matrix[0][2] * coeff[2] - matrix[0][1] * coeff[1]) / matrix[0][0]; // a
|
||||
}
|
||||
|
||||
// 计算一元一次函数在给定区间内开始变成负值的点
|
||||
double findNegativeStartPoint(double m, double b, double start, double end) {
|
||||
double findNegativeStartPoint(double m, double b, double start, double end)
|
||||
{
|
||||
// 处理斜率为零的情况
|
||||
if (m == 0) {
|
||||
if (m == 0)
|
||||
{
|
||||
// 当斜率为 0 时,函数值为常数 b
|
||||
if (b < 0) {
|
||||
return start; // 若 b 为负,函数在区间起始点就为负
|
||||
} else {
|
||||
return std::numeric_limits<double>::infinity(); // 若 b 非负,函数在区间内不会变负
|
||||
if (b < 0)
|
||||
{
|
||||
return start; // 若 b 为负,函数在区间起始点就为负
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::numeric_limits<double>::infinity(); // 若 b 非负,函数在区间内不会变负
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,20 +133,26 @@ namespace Global {
|
||||
double zeroPoint = -b / m;
|
||||
|
||||
// 检查零点是否在给定区间内
|
||||
if (zeroPoint >= start && zeroPoint <= end) {
|
||||
return zeroPoint; // 零点在区间内,函数在此点开始变负
|
||||
if (zeroPoint >= start && zeroPoint <= end)
|
||||
{
|
||||
return zeroPoint; // 零点在区间内,函数在此点开始变负
|
||||
}
|
||||
|
||||
// 根据斜率正负判断函数单调性,进而判断函数在区间内是否会变负
|
||||
if (m > 0) {
|
||||
if (m > 0)
|
||||
{
|
||||
// 斜率大于 0,函数单调递增
|
||||
if (m * start + b < 0) {
|
||||
return start; // 起始点函数值为负,函数在起始点就为负
|
||||
if (m * start + b < 0)
|
||||
{
|
||||
return start; // 起始点函数值为负,函数在起始点就为负
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// 斜率小于 0,函数单调递减
|
||||
if (m * end + b < 0) {
|
||||
return end; // 结束点函数值为负,函数在结束点开始为负
|
||||
if (m * end + b < 0)
|
||||
{
|
||||
return end; // 结束点函数值为负,函数在结束点开始为负
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,22 +160,26 @@ namespace Global {
|
||||
return std::numeric_limits<double>::infinity();
|
||||
}
|
||||
|
||||
void clearExperimentData() {
|
||||
void clearExperimentData()
|
||||
{
|
||||
_curveExperimentDataVtr.clear();
|
||||
_currentCurveExperimentDataPtr = nullptr;
|
||||
_currentPhase = -1;
|
||||
_currentPhase = -1;
|
||||
}
|
||||
|
||||
bool isZero(double value, double epsilon) {
|
||||
bool isZero(double value, double epsilon)
|
||||
{
|
||||
return std::abs(value) < epsilon;
|
||||
}
|
||||
|
||||
bool isEqual(const double a, const double b) {
|
||||
const double tolerance = 1e-5; // 容差值,可以根据需要调整
|
||||
bool isEqual(const double a, const double b)
|
||||
{
|
||||
const double tolerance = 1e-5; // 容差值,可以根据需要调整
|
||||
return std::fabs(a - b) < tolerance;
|
||||
}
|
||||
|
||||
QString getFileName(const QString filePath) {
|
||||
QString getFileName(const QString filePath)
|
||||
{
|
||||
QFileInfo fileInfo(filePath);
|
||||
|
||||
// 获取文件的后缀名并转换为小写,方便比较
|
||||
@ -162,35 +188,37 @@ namespace Global {
|
||||
return fileInfo.fileName();
|
||||
}
|
||||
|
||||
double converStrToDouble(const QString str) {
|
||||
bool ok;
|
||||
double value = str.toDouble(&ok); // 将字符串转换为 double,并检查是否成功
|
||||
if (!ok) {
|
||||
double converStrToDouble(const QString str)
|
||||
{
|
||||
bool ok;
|
||||
double value = str.toDouble(&ok); // 将字符串转换为 double,并检查是否成功
|
||||
if (!ok)
|
||||
{
|
||||
qDebug() << "转换失败,输入的字符串不是有效的数字";
|
||||
return 0.0; // 如果转换失败,返回默认值
|
||||
return 0.0; // 如果转换失败,返回默认值
|
||||
}
|
||||
return value;
|
||||
}
|
||||
bool isFileExist(const QString &fileName) {
|
||||
bool isFileExist(const QString &fileName)
|
||||
{
|
||||
return _fileList.contains(fileName);
|
||||
}
|
||||
|
||||
|
||||
void updateFileList()
|
||||
{
|
||||
_fileList.clear();
|
||||
void updateFileList()
|
||||
{
|
||||
_fileList.clear();
|
||||
|
||||
QDir dir(SampleDataFloder);
|
||||
_fileList.append(dir.entryList(QDir::Files));
|
||||
QDir dir(SampleDataFloder);
|
||||
_fileList.append(dir.entryList(QDir::Files));
|
||||
#if 0
|
||||
dir.setPath(BaseLineFolder);
|
||||
_fileList.append(dir.entryList(QDir::Files));
|
||||
#endif
|
||||
dir.setPath(AnalysisStateFolder);
|
||||
_fileList.append(dir.entryList(QDir::Files));
|
||||
}
|
||||
dir.setPath(AnalysisStateFolder);
|
||||
_fileList.append(dir.entryList(QDir::Files));
|
||||
}
|
||||
|
||||
} // namespace Global
|
||||
} // namespace Global
|
||||
|
||||
#if 0
|
||||
Global::Global()
|
||||
|
||||
@ -31,7 +31,8 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
_coefficientSelectionForm(new CoefficientSelectionForm(this)),
|
||||
_printPreviewForm(new PrintPreviewForm(this)),
|
||||
_axisSettingForm(new AxisSettingForm(this)),
|
||||
_manuallyStopTheExperimentFlag(false) {
|
||||
_manuallyStopTheExperimentFlag(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->actionOITAutoAnalysisMode->setVisible(false);
|
||||
ui->toolBar->setWindowTitle("工具栏");
|
||||
@ -84,44 +85,58 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
// ui->actionStop->setEnabled(false);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::slotContextMenuShow(const QPoint point) {
|
||||
void MainWindow::slotContextMenuShow(const QPoint point)
|
||||
{
|
||||
_contextMenu->exec(point);
|
||||
}
|
||||
|
||||
void MainWindow::slotUpdateStatusbarMsg(const QString msg) {
|
||||
void MainWindow::slotUpdateStatusbarMsg(const QString msg)
|
||||
{
|
||||
ui->statusbar->showMessage(msg);
|
||||
}
|
||||
|
||||
void MainWindow::slotOITAutoAnalysis(const double x1, const double x2) {
|
||||
void MainWindow::slotOITAutoAnalysis(const double x1, const double x2)
|
||||
{
|
||||
on_actionStop_triggered();
|
||||
_centralWidget->setAnalysisMode(CentralWidget::AnalysisMode::OIT);
|
||||
_centralWidget->setVerticalLineRange(x1, x2);
|
||||
}
|
||||
|
||||
void MainWindow::slotStartExperiment() {
|
||||
void MainWindow::slotStartExperiment()
|
||||
{
|
||||
startExperimentByDeviceInfo();
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event) {
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
// 弹出确认对话框
|
||||
QMessageBox::StandardButton reply;
|
||||
reply = QMessageBox::question(this, "确认退出", "你确定要退出吗?",
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
if (reply == QMessageBox::Yes) {
|
||||
event->accept(); // 接受关闭事件,关闭窗口
|
||||
} else {
|
||||
event->ignore(); // 忽略关闭事件,不关闭窗口
|
||||
if (reply == QMessageBox::Yes)
|
||||
{
|
||||
event->accept(); // 接受关闭事件,关闭窗口
|
||||
}
|
||||
else
|
||||
{
|
||||
event->ignore(); // 忽略关闭事件,不关闭窗口
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::connections() {
|
||||
void MainWindow::connections()
|
||||
{
|
||||
// ui
|
||||
connect(_expertmentSettingForm, &ExperimentSettingForm::sigDeliverData,
|
||||
SerialPort::instance(), &SerialPort::slotDeliverData);
|
||||
|
||||
// 左侧文件管理子窗口相关函数
|
||||
connect(_leftWidget, &LeftWidget::sigDeleteActionTriggered,
|
||||
this, &MainWindow::slotDeleteActionTriggered);
|
||||
#if 1
|
||||
// SerialPort.
|
||||
connect(SerialPort::instance(), &SerialPort::sigSendCommonData,
|
||||
@ -172,7 +187,8 @@ void MainWindow::connections() {
|
||||
_centralWidget, &CentralWidget::slotAnalysisSettingCancel);
|
||||
|
||||
connect(_centralWidget, &CentralWidget::sigRightDockWidgetHide,
|
||||
[&]() { _rightWidget->hide(); });
|
||||
[&]()
|
||||
{ _rightWidget->hide(); });
|
||||
|
||||
connect(_degreeOfCrystallinityForm, &DegreeOfCrystallinityForm::sigDrawCustomText,
|
||||
_centralWidget, &CentralWidget::slotDrawCustomText);
|
||||
@ -196,13 +212,17 @@ void MainWindow::connections() {
|
||||
this, &MainWindow::slotOITAutoAnalysis);
|
||||
}
|
||||
|
||||
void MainWindow::setActionEnable(const bool flag) {
|
||||
if (flag) {
|
||||
void MainWindow::setActionEnable(const bool flag)
|
||||
{
|
||||
if (flag)
|
||||
{
|
||||
ui->actionNew->setEnabled(true);
|
||||
ui->actionStart->setEnabled(true);
|
||||
ui->actionStop->setEnabled(true);
|
||||
ui->actionRealTimeWidget->setEnabled(true);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->actionNew->setEnabled(false);
|
||||
ui->actionStart->setEnabled(false);
|
||||
ui->actionStop->setEnabled(false);
|
||||
@ -210,7 +230,8 @@ void MainWindow::setActionEnable(const bool flag) {
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setSubWidgetAttribute(QWidget *widget) {
|
||||
void MainWindow::setSubWidgetAttribute(QWidget *widget)
|
||||
{
|
||||
widget->setWindowModality(Qt::ApplicationModal);
|
||||
widget->setWindowFlags(Qt::Dialog);
|
||||
|
||||
@ -262,48 +283,63 @@ bool MainWindow::saveAnalysisFile(const QString fileName)
|
||||
#endif
|
||||
|
||||
bool MainWindow::saveFile(const QString fileName, const Global::Mode mode,
|
||||
QString &finalFileName, const bool autoSaveFlag) {
|
||||
QString &finalFileName, const bool autoSaveFlag)
|
||||
{
|
||||
logde << "save file...";
|
||||
|
||||
QString localFileName = fileName;
|
||||
if (fileName.isEmpty()) {
|
||||
if (fileName.isEmpty())
|
||||
{
|
||||
localFileName = "new";
|
||||
}
|
||||
|
||||
QString folder;
|
||||
if (mode == Global::Mode::None) {
|
||||
if (mode == Global::Mode::None)
|
||||
{
|
||||
folder = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
} else if (mode == Global::Mode::Analysis) {
|
||||
}
|
||||
else if (mode == Global::Mode::Analysis)
|
||||
{
|
||||
folder = Global::AnalysisStateFolder;
|
||||
} else if (mode == Global::Mode::Experiment) {
|
||||
}
|
||||
else if (mode == Global::Mode::Experiment)
|
||||
{
|
||||
folder = Global::SampleDataFloder;
|
||||
}
|
||||
|
||||
QString filePath;
|
||||
if (autoSaveFlag) {
|
||||
if (autoSaveFlag)
|
||||
{
|
||||
localFileName = _leftWidget->filePathCheck(fileName, folder);
|
||||
filePath = folder + "/" + localFileName + ".xlsx";
|
||||
} else {
|
||||
filePath = folder + "/" + localFileName + ".xlsx";
|
||||
}
|
||||
else
|
||||
{
|
||||
QString xlsxfilePath = folder + "/" + localFileName + ".xlsx";
|
||||
filePath = QFileDialog::getSaveFileName(nullptr, "Save experiment file",
|
||||
xlsxfilePath, "Excel Files (*.xlsx)");
|
||||
filePath = QFileDialog::getSaveFileName(nullptr, "Save experiment file",
|
||||
xlsxfilePath, "Excel Files (*.xlsx)");
|
||||
}
|
||||
//
|
||||
finalFileName = localFileName + ".xlsx";
|
||||
|
||||
logde << "filePath:" << filePath.toStdString();
|
||||
|
||||
if (filePath.isEmpty()) {
|
||||
if (filePath.isEmpty())
|
||||
{
|
||||
qDebug() << "User cancel the operation.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save file.
|
||||
if (mode == Global::Mode::Analysis) {
|
||||
if (Global::_curveFileDataVtr.empty()) {
|
||||
if (mode == Global::Mode::Analysis)
|
||||
{
|
||||
if (Global::_curveFileDataVtr.empty())
|
||||
{
|
||||
// 分析模式下,但是文件数据为空,说明做完实验没有保存数据。
|
||||
XlsxHandler::writeExperimentFile(filePath);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// 分析模式下,存在文件数据,将文件数据写入文件。
|
||||
XlsxHandler::writeXlsxFile(filePath);
|
||||
#if 0
|
||||
@ -316,57 +352,72 @@ bool MainWindow::saveFile(const QString fileName, const Global::Mode mode,
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else if (mode == Global::Mode::Experiment) {
|
||||
}
|
||||
else if (mode == Global::Mode::Experiment)
|
||||
{
|
||||
XlsxHandler::writeExperimentFile(filePath);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::smoothness(const int level) {
|
||||
void MainWindow::smoothness(const int level)
|
||||
{
|
||||
logde << "smoothness...";
|
||||
slotUpdateStatusbarMsg("数据平滑计算中...");
|
||||
|
||||
if (!Global::_curveExperimentDataVtr.empty()) {
|
||||
if (!Global::_curveExperimentDataVtr.empty())
|
||||
{
|
||||
// 当前数据为实验数据时,需要把所有的当前实验数据都进行平滑处理。
|
||||
|
||||
// 删除所有objectName为experiment的curve.
|
||||
_centralWidget->deleteCurveByObjectName(Global::ObjectNameExperiemnt);
|
||||
// 添加所有平滑后的curve.
|
||||
for (auto &item : Global::_curveExperimentDataVtr) {
|
||||
for (auto &item : Global::_curveExperimentDataVtr)
|
||||
{
|
||||
item.smoothDataVtr = smoothnessDetail(level, item.dataVtr);
|
||||
item.curve = _centralWidget->addCurveData(item.smoothDataVtr,
|
||||
Global::ObjectNameExperiemnt);
|
||||
item.curve = _centralWidget->addCurveData(item.smoothDataVtr,
|
||||
Global::ObjectNameExperiemnt);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// 当前数据为文件分析数据时,需要把当前文件下的所有数据都进行平滑处理。
|
||||
QString selectedCurveObjectName = _centralWidget->getCurrentCurve()->objectName();
|
||||
_centralWidget->deleteCurveByObjectName(selectedCurveObjectName);
|
||||
|
||||
for (Global::CurveFileData &cfd : Global::_curveFileDataVtr) {
|
||||
if (selectedCurveObjectName.contains(cfd.filePath)) {
|
||||
for (Global::PhaseTotalInfo &pti : cfd.phaseTotalVtr) {
|
||||
for (Global::CurveFileData &cfd : Global::_curveFileDataVtr)
|
||||
{
|
||||
if (selectedCurveObjectName.contains(cfd.filePath))
|
||||
{
|
||||
for (Global::PhaseTotalInfo &pti : cfd.phaseTotalVtr)
|
||||
{
|
||||
pti.smoothDataVtr = smoothnessDetail(level, pti.dataVtr);
|
||||
pti.curve = _centralWidget->addCurveData(pti.smoothDataVtr,
|
||||
cfd.filePath);
|
||||
pti.curve = _centralWidget->addCurveData(pti.smoothDataVtr,
|
||||
cfd.filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVector<Global::ExperimentData> MainWindow::smoothnessDetail(const int level, const QVector<Global::ExperimentData> &dataVtr) {
|
||||
QVector<Global::ExperimentData> MainWindow::smoothnessDetail(const int level, const QVector<Global::ExperimentData> &dataVtr)
|
||||
{
|
||||
Lowess::Config config;
|
||||
config.smoothingFactor = level * 0.01;
|
||||
config.smoothingFactor = level * 0.01;
|
||||
config.robustnessIterations = 3;
|
||||
|
||||
std::vector<double> x;
|
||||
std::vector<double> y;
|
||||
|
||||
for (const Global::ExperimentData &ed : dataVtr) {
|
||||
if (Global::_axisMode == Global::AxisMode::SingleY) {
|
||||
for (const Global::ExperimentData &ed : dataVtr)
|
||||
{
|
||||
if (Global::_axisMode == Global::AxisMode::SingleY)
|
||||
{
|
||||
x.push_back(ed.sampleTemp);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
x.push_back(ed.runTime);
|
||||
}
|
||||
|
||||
@ -385,7 +436,8 @@ QVector<Global::ExperimentData> MainWindow::smoothnessDetail(const int level, co
|
||||
ui->statusbar->showMessage("数据平滑计算中...");
|
||||
|
||||
std::vector<double> yest = Lowess::smooth(x, y, config);
|
||||
if (yest.empty()) {
|
||||
if (yest.empty())
|
||||
{
|
||||
slotUpdateStatusbarMsg("数据平滑完成.");
|
||||
return resultVtr;
|
||||
}
|
||||
@ -396,17 +448,21 @@ QVector<Global::ExperimentData> MainWindow::smoothnessDetail(const int level, co
|
||||
|
||||
// result data vector.
|
||||
|
||||
for (int i = 0; i < x.size(); i++) {
|
||||
for (int i = 0; i < x.size(); i++)
|
||||
{
|
||||
Global::ExperimentData ed;
|
||||
if (Global::_axisMode == Global::AxisMode::SingleY) {
|
||||
if (Global::_axisMode == Global::AxisMode::SingleY)
|
||||
{
|
||||
ed.sampleTemp = x.at(i);
|
||||
ed.runTime = dataVtr.at(i).runTime;
|
||||
} else {
|
||||
ed.runTime = x.at(i);
|
||||
ed.runTime = dataVtr.at(i).runTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
ed.runTime = x.at(i);
|
||||
ed.sampleTemp = dataVtr.at(i).sampleTemp;
|
||||
}
|
||||
|
||||
ed.dsc = yest.at(i);
|
||||
ed.dsc = yest.at(i);
|
||||
ed.constantTempTime = dataVtr.at(i).constantTempTime;
|
||||
|
||||
resultVtr.push_back(ed);
|
||||
@ -415,7 +471,8 @@ QVector<Global::ExperimentData> MainWindow::smoothnessDetail(const int level, co
|
||||
return resultVtr;
|
||||
}
|
||||
|
||||
void MainWindow::smoothnessExperimentData(const int level) {
|
||||
void MainWindow::smoothnessExperimentData(const int level)
|
||||
{
|
||||
#if 0
|
||||
for(int i = 0;i < Global::_curveExperimentDataVtr.size();i++){
|
||||
Global::CurveExperimentData ced = Global::_curveExperimentDataVtr.at(i);
|
||||
@ -423,19 +480,21 @@ void MainWindow::smoothnessExperimentData(const int level) {
|
||||
}
|
||||
#endif
|
||||
|
||||
for (auto &item : Global::_curveExperimentDataVtr) {
|
||||
for (auto &item : Global::_curveExperimentDataVtr)
|
||||
{
|
||||
smoothnessDetail(level, item.dataVtr);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::startExperiment() {
|
||||
void MainWindow::startExperiment()
|
||||
{
|
||||
QByteArray ba = DataParser::setDeviceStartStop(DeviceStartMode::Start);
|
||||
|
||||
QString hexData = ba.toHex(' ');
|
||||
|
||||
SerialPort::instance()->slotSendData(ba);
|
||||
|
||||
Global::_mode = Global::Mode::Experiment;
|
||||
Global::_mode = Global::Mode::Experiment;
|
||||
_manuallyStopTheExperimentFlag = false;
|
||||
_centralWidget->startExperiment();
|
||||
|
||||
@ -445,8 +504,9 @@ void MainWindow::startExperiment() {
|
||||
ui->menu_4->menuAction()->setEnabled(false);
|
||||
}
|
||||
|
||||
void MainWindow::startExperimentByDeviceInfo() {
|
||||
Global::_mode = Global::Mode::Experiment;
|
||||
void MainWindow::startExperimentByDeviceInfo()
|
||||
{
|
||||
Global::_mode = Global::Mode::Experiment;
|
||||
_manuallyStopTheExperimentFlag = false;
|
||||
_centralWidget->startExperiment();
|
||||
|
||||
@ -454,15 +514,18 @@ void MainWindow::startExperimentByDeviceInfo() {
|
||||
Global::clearExperimentData();
|
||||
}
|
||||
// 停止实验
|
||||
void MainWindow::on_actionStop_triggered() {
|
||||
void MainWindow::on_actionStop_triggered()
|
||||
{
|
||||
logde << " Stop experiment ...++++++++++++++++++";
|
||||
|
||||
if (!SerialPort::instance()->isOpen()) {
|
||||
if (!SerialPort::instance()->isOpen())
|
||||
{
|
||||
showMesgBox("设备未连接,请先连接设备。");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Global::_mode == Global::Mode::Experiment) {
|
||||
if (Global::_mode == Global::Mode::Experiment)
|
||||
{
|
||||
QByteArray ba = DataParser::setDeviceStartStop(DeviceStartMode::Stop);
|
||||
SerialPort::instance()->slotSendData(ba);
|
||||
|
||||
@ -477,7 +540,8 @@ void MainWindow::on_actionStop_triggered() {
|
||||
logde << "on_actionStop_triggered saveFile ...";
|
||||
|
||||
QString finalFileName;
|
||||
if (saveFile(Global::_experimentInfo.sampleName, Global::Mode::Experiment, finalFileName, true)) {
|
||||
if (saveFile(Global::_experimentInfo.sampleName, Global::Mode::Experiment, finalFileName, true))
|
||||
{
|
||||
_leftWidget->reloadFileName();
|
||||
|
||||
QString str = QString("%1 文件保存成功。").arg(finalFileName);
|
||||
@ -492,19 +556,23 @@ void MainWindow::on_actionStop_triggered() {
|
||||
ui->menu_4->menuAction()->setEnabled(true);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionNew_triggered() {
|
||||
if (!SerialPort::instance()->isOpen()) {
|
||||
void MainWindow::on_actionNew_triggered()
|
||||
{
|
||||
if (!SerialPort::instance()->isOpen())
|
||||
{
|
||||
showMesgBox("设备未连接,请先连接设备。");
|
||||
return;
|
||||
}
|
||||
_expertmentSettingForm->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionStart_triggered() {
|
||||
void MainWindow::on_actionStart_triggered()
|
||||
{
|
||||
logde << "start experiment,set soft into experiment mode.";
|
||||
logde << "```````````````````````````````";
|
||||
|
||||
if (!SerialPort::instance()->isOpen()) {
|
||||
if (!SerialPort::instance()->isOpen())
|
||||
{
|
||||
showMesgBox("设备未连接,请先连接设备。");
|
||||
return;
|
||||
}
|
||||
@ -514,19 +582,23 @@ void MainWindow::on_actionStart_triggered() {
|
||||
startExperiment();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionReadOnly_triggered() {
|
||||
void MainWindow::on_actionReadOnly_triggered()
|
||||
{
|
||||
Global::_mode = Global::Mode::Experiment;
|
||||
SerialPort::instance()->openSp();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionRealTimeWidget_triggered() {
|
||||
void MainWindow::on_actionRealTimeWidget_triggered()
|
||||
{
|
||||
_realTimeDataForm->show();
|
||||
}
|
||||
|
||||
void MainWindow::slotSaveExperimentalDataMsgBox() {
|
||||
void MainWindow::slotSaveExperimentalDataMsgBox()
|
||||
{
|
||||
logde << "_manuallyStopTheExperimentFlag:" << _manuallyStopTheExperimentFlag;
|
||||
|
||||
if (_manuallyStopTheExperimentFlag) {
|
||||
if (_manuallyStopTheExperimentFlag)
|
||||
{
|
||||
logde << "_manuallyStopTheExperimentFlag...";
|
||||
return;
|
||||
}
|
||||
@ -537,7 +609,8 @@ void MainWindow::slotSaveExperimentalDataMsgBox() {
|
||||
if (saveFile(Global::_experimentInfo.sampleName,
|
||||
Global::Mode::Experiment,
|
||||
finalFileName,
|
||||
true)) {
|
||||
true))
|
||||
{
|
||||
_leftWidget->reloadFileName();
|
||||
|
||||
QString str = QString("%1 文件保存成功。").arg(finalFileName);
|
||||
@ -564,10 +637,12 @@ void MainWindow::slotSaveExperimentalDataMsgBox() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::on_actionConnectToDev_triggered() {
|
||||
void MainWindow::on_actionConnectToDev_triggered()
|
||||
{
|
||||
logde << "connect to device...";
|
||||
|
||||
if (SerialPort::instance()->isOpen()) {
|
||||
if (SerialPort::instance()->isOpen())
|
||||
{
|
||||
logde << "close device.";
|
||||
|
||||
SerialPort::instance()->closeSp();
|
||||
@ -580,10 +655,13 @@ void MainWindow::on_actionConnectToDev_triggered() {
|
||||
QString str("设备已断开。");
|
||||
slotUpdateStatusbarMsg(str);
|
||||
showMesgBox(str);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
logde << "open device.";
|
||||
|
||||
if (SerialPort::instance()->openSp()) {
|
||||
if (SerialPort::instance()->openSp())
|
||||
{
|
||||
setActionEnable(true);
|
||||
// Global::instance()->setMode(Global::Mode::ConnectedToDev);
|
||||
Global::_mode = Global::Mode::ConnectedToDev;
|
||||
@ -600,38 +678,46 @@ void MainWindow::on_actionConnectToDev_triggered() {
|
||||
showMesgBox(str);
|
||||
|
||||
logde << "open serial port success. ";
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// QMessageBox::warning(this, "warnning", "Serial Port open failed.");
|
||||
showMesgBox("设备打开失败。");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionStartPoint_triggered() {
|
||||
void MainWindow::on_actionStartPoint_triggered()
|
||||
{
|
||||
logde << "start experiment...";
|
||||
|
||||
_rightWidget->show();
|
||||
_centralWidget->setAnalysisMode(CentralWidget::AnalysisMode::StartPoint);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionStopPoint_triggered() {
|
||||
void MainWindow::on_actionStopPoint_triggered()
|
||||
{
|
||||
_rightWidget->show();
|
||||
_centralWidget->setAnalysisMode(CentralWidget::AnalysisMode::StopPoint);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionNumericalLabel_triggered() {
|
||||
void MainWindow::on_actionNumericalLabel_triggered()
|
||||
{
|
||||
_rightWidget->show();
|
||||
_centralWidget->setAnalysisMode(CentralWidget::AnalysisMode::NumericalLabel);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionPeakSynthesisAnalysis_triggered() {
|
||||
void MainWindow::on_actionPeakSynthesisAnalysis_triggered()
|
||||
{
|
||||
_rightWidget->show();
|
||||
_centralWidget->setAnalysisMode(CentralWidget::AnalysisMode::PeakSynthesisAnalysis);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionClearAllData_triggered() {
|
||||
void MainWindow::on_actionClearAllData_triggered()
|
||||
{
|
||||
// 实验过程中,不允许清除数据。
|
||||
if (Global::_mode == Global::Mode::Experiment) {
|
||||
if (Global::_mode == Global::Mode::Experiment)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@ -641,62 +727,75 @@ void MainWindow::on_actionClearAllData_triggered() {
|
||||
_centralWidget->clearAllData();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionGlassTransition_triggered() {
|
||||
void MainWindow::on_actionGlassTransition_triggered()
|
||||
{
|
||||
_rightWidget->show();
|
||||
_centralWidget->setAnalysisMode(CentralWidget::AnalysisMode::GlassTransition);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionOIT_triggered() {
|
||||
void MainWindow::on_actionOIT_triggered()
|
||||
{
|
||||
_rightWidget->show();
|
||||
_centralWidget->setAnalysisMode(CentralWidget::AnalysisMode::OIT);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionSpecificHeatCompMethod_triggered() {
|
||||
void MainWindow::on_actionSpecificHeatCompMethod_triggered()
|
||||
{
|
||||
_specificHeatComparisonMethodForm->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionDegreeOfCrystallinity_triggered() {
|
||||
void MainWindow::on_actionDegreeOfCrystallinity_triggered()
|
||||
{
|
||||
// QMessageBox::warning(this, "warnning", "结晶度.");
|
||||
_degreeOfCrystallinityForm->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionInstrumentParameter_triggered() {
|
||||
void MainWindow::on_actionInstrumentParameter_triggered()
|
||||
{
|
||||
_instrumentCoefficientForm->show();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::on_actionOITAutoAnalysisParam_triggered() {
|
||||
void MainWindow::on_actionOITAutoAnalysisParam_triggered()
|
||||
{
|
||||
_OITAutoAnalysisParamForm->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionOITAutoAnalysisMode_triggered() {
|
||||
void MainWindow::on_actionOITAutoAnalysisMode_triggered()
|
||||
{
|
||||
}
|
||||
|
||||
void MainWindow::on_actionTimeAxisAnalysisPCTMode_triggered() {
|
||||
void MainWindow::on_actionTimeAxisAnalysisPCTMode_triggered()
|
||||
{
|
||||
Global::_displayTimeValue = ui->actionTimeAxisAnalysisPCTMode->isChecked();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionDegreeOfCuring_triggered() {
|
||||
void MainWindow::on_actionDegreeOfCuring_triggered()
|
||||
{
|
||||
//
|
||||
_degreeOfCureForm->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionAbout_triggered() {
|
||||
void MainWindow::on_actionAbout_triggered()
|
||||
{
|
||||
_aboutForm->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionEnthalpyCorrectionEdit_triggered() {
|
||||
void MainWindow::on_actionEnthalpyCorrectionEdit_triggered()
|
||||
{
|
||||
_enthalpyDataCorrectionForm->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionEnthalpyCorrectionSelection_triggered() {
|
||||
void MainWindow::on_actionEnthalpyCorrectionSelection_triggered()
|
||||
{
|
||||
_coefficientSelectionForm->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionPrintPreview_triggered() {
|
||||
void MainWindow::on_actionPrintPreview_triggered()
|
||||
{
|
||||
logde << "print preview...";
|
||||
|
||||
if (Global::_curveFileDataVtr.empty()) {
|
||||
if (Global::_curveFileDataVtr.empty())
|
||||
{
|
||||
showMesgBox("请先打开数据。");
|
||||
return;
|
||||
}
|
||||
@ -706,103 +805,132 @@ void MainWindow::on_actionPrintPreview_triggered() {
|
||||
// _printPreviewForm->setOrientation();
|
||||
|
||||
_printPreviewForm->_customPrintPreviewDialog->exec();
|
||||
_printPreviewForm->_customPrintPreviewDialog->update(); // 可选,强制刷新
|
||||
_printPreviewForm->_customPrintPreviewDialog->update(); // 可选,强制刷新
|
||||
}
|
||||
|
||||
void MainWindow::on_actionOnsetTemperaturePoint_triggered() {
|
||||
void MainWindow::on_actionOnsetTemperaturePoint_triggered()
|
||||
{
|
||||
_rightWidget->show();
|
||||
_centralWidget->setAnalysisMode(CentralWidget::AnalysisMode::OnsetTemperaturePoint);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionEndsetTemperaturePoint_triggered() {
|
||||
void MainWindow::on_actionEndsetTemperaturePoint_triggered()
|
||||
{
|
||||
_rightWidget->show();
|
||||
_centralWidget->setAnalysisMode(CentralWidget::AnalysisMode::EndsetTemperaturePoint);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionYAxis_triggered() {
|
||||
void MainWindow::on_actionYAxis_triggered()
|
||||
{
|
||||
_centralWidget->switchAxisMode();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionAxisSetting_triggered() {
|
||||
void MainWindow::on_actionAxisSetting_triggered()
|
||||
{
|
||||
_axisSettingForm->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionSaveData_triggered() {
|
||||
void MainWindow::on_actionSaveData_triggered()
|
||||
{
|
||||
QString finaleFileName;
|
||||
saveFile(Global::_experimentInfo.sampleName, Global::_mode, finaleFileName);
|
||||
_leftWidget->reloadFileName();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionSaveas_triggered() {
|
||||
void MainWindow::on_actionSaveas_triggered()
|
||||
{
|
||||
QString finaleFileName;
|
||||
saveFile(Global::_experimentInfo.sampleName, Global::Mode::None, finaleFileName);
|
||||
_leftWidget->reloadFileName();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionLanguage_triggered() {
|
||||
if (Global::_languageType == Global::LanguageType::Chinese) {
|
||||
void MainWindow::on_actionLanguage_triggered()
|
||||
{
|
||||
if (Global::_languageType == Global::LanguageType::Chinese)
|
||||
{
|
||||
Global::_languageType = Global::LanguageType::English;
|
||||
ui->actionLanguage->setText(Global::EnglishStr);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Global::_languageType = Global::LanguageType::Chinese;
|
||||
ui->actionLanguage->setText(Global::ChineseStr);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionSmoothness1_triggered() {
|
||||
void MainWindow::on_actionSmoothness1_triggered()
|
||||
{
|
||||
smoothness(1);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionSmoothness2_triggered() {
|
||||
void MainWindow::on_actionSmoothness2_triggered()
|
||||
{
|
||||
smoothness(2);
|
||||
}
|
||||
void MainWindow::on_actionSmoothness3_triggered() {
|
||||
void MainWindow::on_actionSmoothness3_triggered()
|
||||
{
|
||||
smoothness(3);
|
||||
}
|
||||
void MainWindow::on_actionSmoothness4_triggered() {
|
||||
void MainWindow::on_actionSmoothness4_triggered()
|
||||
{
|
||||
smoothness(4);
|
||||
}
|
||||
void MainWindow::on_actionSmoothness5_triggered() {
|
||||
void MainWindow::on_actionSmoothness5_triggered()
|
||||
{
|
||||
smoothness(5);
|
||||
}
|
||||
void MainWindow::on_actionSmoothness6_triggered() {
|
||||
void MainWindow::on_actionSmoothness6_triggered()
|
||||
{
|
||||
smoothness(6);
|
||||
}
|
||||
void MainWindow::on_actionSmoothness7_triggered() {
|
||||
void MainWindow::on_actionSmoothness7_triggered()
|
||||
{
|
||||
smoothness(7);
|
||||
}
|
||||
void MainWindow::on_actionSmoothness8_triggered() {
|
||||
void MainWindow::on_actionSmoothness8_triggered()
|
||||
{
|
||||
smoothness(8);
|
||||
}
|
||||
void MainWindow::on_actionSmoothness9_triggered() {
|
||||
void MainWindow::on_actionSmoothness9_triggered()
|
||||
{
|
||||
smoothness(9);
|
||||
}
|
||||
void MainWindow::on_actionSmoothness10_triggered() {
|
||||
void MainWindow::on_actionSmoothness10_triggered()
|
||||
{
|
||||
smoothness(10);
|
||||
}
|
||||
|
||||
// 原始数据
|
||||
void MainWindow::on_actionOriginalData_triggered() {
|
||||
if (!Global::_curveExperimentDataVtr.empty()) {
|
||||
void MainWindow::on_actionOriginalData_triggered()
|
||||
{
|
||||
if (!Global::_curveExperimentDataVtr.empty())
|
||||
{
|
||||
// 删除所有objectName为experiment的curve.
|
||||
_centralWidget->deleteCurveByObjectName(Global::ObjectNameExperiemnt);
|
||||
|
||||
for (auto &item : Global::_curveExperimentDataVtr) {
|
||||
for (auto &item : Global::_curveExperimentDataVtr)
|
||||
{
|
||||
item.smoothDataVtr.clear();
|
||||
item.curve = _centralWidget->addCurveData(item.dataVtr, Global::ObjectNameExperiemnt);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// 当前数据为文件分析数据时,需要把当前文件下的所有数据都进行平滑处理。
|
||||
if(_centralWidget->getCurrentCurve() == nullptr){
|
||||
if (_centralWidget->getCurrentCurve() == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QString selectedCurveObjectName = _centralWidget->getCurrentCurve()->objectName();
|
||||
_centralWidget->deleteCurveByObjectName(selectedCurveObjectName);
|
||||
|
||||
for (Global::CurveFileData &cfd : Global::_curveFileDataVtr) {
|
||||
if (selectedCurveObjectName.contains(cfd.filePath)) {
|
||||
for (Global::PhaseTotalInfo &pti : cfd.phaseTotalVtr) {
|
||||
for (Global::CurveFileData &cfd : Global::_curveFileDataVtr)
|
||||
{
|
||||
if (selectedCurveObjectName.contains(cfd.filePath))
|
||||
{
|
||||
for (Global::PhaseTotalInfo &pti : cfd.phaseTotalVtr)
|
||||
{
|
||||
pti.smoothDataVtr.clear();
|
||||
pti.curve = _centralWidget->addCurveData(pti.dataVtr,
|
||||
cfd.filePath);
|
||||
@ -847,19 +975,23 @@ void MainWindow::on_actionOriginalData_triggered() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::showMesgBox(const QString str) {
|
||||
void MainWindow::showMesgBox(const QString str)
|
||||
{
|
||||
static bool isShow = false;
|
||||
if (!isShow) {
|
||||
if (!isShow)
|
||||
{
|
||||
isShow = true;
|
||||
QMessageBox::information(this, "提示", str);
|
||||
isShow = false;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::slotDeviceDisconnected() {
|
||||
void MainWindow::slotDeviceDisconnected()
|
||||
{
|
||||
// logde<<"slotDeviceDisconnected...1";
|
||||
// 如果当前是实验模式时,需要先停止实验。
|
||||
if (SerialPort::instance()->isOpen()) {
|
||||
if (SerialPort::instance()->isOpen())
|
||||
{
|
||||
// logde<<"slotDeviceDisconnected...2";
|
||||
// ui更新,断开连接
|
||||
ui->actionConnectToDev->setIcon(QIcon(":/images/connect.png"));
|
||||
@ -870,3 +1002,17 @@ void MainWindow::slotDeviceDisconnected() {
|
||||
SerialPort::instance()->closeSp();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::slotDeleteActionTriggered(const QString &filePath)
|
||||
{
|
||||
logde<<"slotDeleteActionTriggered...1:"<<filePath.toStdString();
|
||||
|
||||
int ret = QMessageBox::question(this,
|
||||
tr("请确认"),
|
||||
tr("确定要删除文件“%1”吗?").arg(filePath),
|
||||
QMessageBox::Ok | QMessageBox::Cancel,
|
||||
QMessageBox::Ok);
|
||||
|
||||
_leftWidget->confirmDelete(ret == QMessageBox::Ok ? true : false);
|
||||
}
|
||||
|
||||
|
||||
@ -45,6 +45,9 @@ public slots:
|
||||
void slotStartExperiment();
|
||||
|
||||
void slotDeviceDisconnected();
|
||||
|
||||
// 左侧文件管理子窗口操作函数
|
||||
void slotDeleteActionTriggered(const QString&);
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
private slots:
|
||||
@ -52,6 +55,7 @@ private slots:
|
||||
void on_actionConnectToDev_triggered();
|
||||
void on_actionNew_triggered();
|
||||
void on_actionStart_triggered();
|
||||
|
||||
// 停止实验
|
||||
void on_actionStop_triggered();
|
||||
void on_actionReadOnly_triggered();
|
||||
|
||||
@ -1,63 +1,59 @@
|
||||
#include <qdir.h>
|
||||
#include <qdebug.h>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QHBoxLayout>
|
||||
#include <QStyle>
|
||||
#include <QFileInfo>
|
||||
#include <QTreeWidgetItemIterator>
|
||||
#include <QTreeWidget>
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QDirIterator>
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QMessageBox>
|
||||
#include <QInputDialog>
|
||||
|
||||
#include "leftwidget.h"
|
||||
#include "filemanager.h"
|
||||
#include "global.h"
|
||||
#include "logger.h"
|
||||
|
||||
LeftWidget::LeftWidget(QWidget *parent) : QDockWidget(parent) {
|
||||
LeftWidget::LeftWidget(QWidget *parent) : QDockWidget(parent)
|
||||
{
|
||||
setWindowTitle("文件浏览");
|
||||
|
||||
_treeWidget = new QTreeWidget();
|
||||
_treeWidget->setHeaderHidden(true);
|
||||
|
||||
_sampleDataItem = new QTreeWidgetItem(_treeWidget);
|
||||
_sampleDataItem->setText(0, "样品数据");
|
||||
#if 0
|
||||
_baseLineItem = new QTreeWidgetItem(_treeWidget);
|
||||
_baseLineItem->setText(0,"基线");
|
||||
#endif
|
||||
_analysisStateItem = new QTreeWidgetItem(_treeWidget);
|
||||
_analysisStateItem->setText(0, "分析状态");
|
||||
|
||||
_treeWidget->setSortingEnabled(false);
|
||||
|
||||
_treeWidget->insertTopLevelItem(0, _sampleDataItem);
|
||||
// _treeWidget->insertTopLevelItem(1, _baseLineItem);
|
||||
_treeWidget->insertTopLevelItem(2, _analysisStateItem);
|
||||
|
||||
setWidget(_treeWidget);
|
||||
|
||||
// init file name.
|
||||
initFileName(_sampleDataItem, Global::SampleDataFloder);
|
||||
#if 0
|
||||
initFileName(_baseLineItem,Global::BaseLineFolder);
|
||||
#endif
|
||||
initFileName(_analysisStateItem, Global::AnalysisStateFolder);
|
||||
|
||||
expandAll(_sampleDataItem);
|
||||
// expandAll(_baseLineItem);
|
||||
expandAll(_analysisStateItem);
|
||||
|
||||
Global::updateFileList();
|
||||
|
||||
// 初始化文件树
|
||||
reloadFileTree();
|
||||
|
||||
// connections
|
||||
connect(_treeWidget, &QTreeWidget::itemDoubleClicked,
|
||||
this, &LeftWidget::slotTreeWidgetItemClicked);
|
||||
|
||||
// 右键菜单
|
||||
_contextMenu = new QMenu(_treeWidget);
|
||||
_deleteAction = new QAction("删除", this);
|
||||
_contextMenu->addAction(_deleteAction);
|
||||
_contextMenu = new QMenu(_treeWidget);
|
||||
_deleteFileAction = new QAction("删除文件", this);
|
||||
_createFolderAction = new QAction("新建文件夹", this);
|
||||
_contextMenu->addAction(_deleteFileAction);
|
||||
_contextMenu->addAction(_createFolderAction);
|
||||
|
||||
_treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
connect(_treeWidget, &QTreeWidget::customContextMenuRequested,
|
||||
this, &LeftWidget::slotShowContextMenu);
|
||||
|
||||
connect(_deleteFileAction, &QAction::triggered,
|
||||
this, &LeftWidget::slotDeleteActionTriggered);
|
||||
connect(_createFolderAction, &QAction::triggered,
|
||||
this, &LeftWidget::slotCreateFolderActionTriggered);
|
||||
}
|
||||
|
||||
void LeftWidget::reloadFileName() {
|
||||
void LeftWidget::reloadFileName()
|
||||
{
|
||||
clearAllChildItems(_sampleDataItem);
|
||||
// clearAllChildItems(_baseLineItem);
|
||||
clearAllChildItems(_analysisStateItem);
|
||||
@ -66,21 +62,25 @@ void LeftWidget::reloadFileName() {
|
||||
#if 0
|
||||
initFileName(_baseLineItem,Global::BaseLineFolder);
|
||||
#endif
|
||||
|
||||
initFileName(_analysisStateItem, Global::AnalysisStateFolder);
|
||||
// 更新文件列表
|
||||
Global::updateFileList();
|
||||
}
|
||||
|
||||
QString LeftWidget::filePathCheck(const QString fileName, const QString folderPath) {
|
||||
QString LeftWidget::filePathCheck(const QString fileName, const QString folderPath)
|
||||
{
|
||||
QString resultFileName = fileName;
|
||||
|
||||
QDir dir(folderPath);
|
||||
QDir dir(folderPath);
|
||||
QStringList files = dir.entryList(QDir::Files);
|
||||
for (const QString &existedFileName : files) {
|
||||
for (const QString &existedFileName : files)
|
||||
{
|
||||
QFileInfo fileInfo(existedFileName);
|
||||
if (fileName == fileInfo.baseName()) {
|
||||
if (fileName == fileInfo.baseName())
|
||||
{
|
||||
QDateTime currentDateTime = QDateTime::currentDateTime();
|
||||
QString formattedTime = currentDateTime.toString("yyyy_MM_dd_HH_mm_ss");
|
||||
QString formattedTime = currentDateTime.toString("yyyy_MM_dd_HH_mm_ss");
|
||||
|
||||
resultFileName = fileName + QString("_") + formattedTime;
|
||||
break;
|
||||
@ -90,70 +90,89 @@ QString LeftWidget::filePathCheck(const QString fileName, const QString folderPa
|
||||
return resultFileName;
|
||||
}
|
||||
|
||||
void LeftWidget::initData() {
|
||||
void LeftWidget::initData()
|
||||
{
|
||||
// const QString folderPath = QDir::currentPath()+"/../experiment_data";
|
||||
const QString folderPath = Global::SampleDataFloder;
|
||||
#if 1
|
||||
QDir dir(folderPath);
|
||||
if (!dir.exists()) {
|
||||
if (!dir.exists())
|
||||
{
|
||||
qWarning() << "文件夹不存在: " << folderPath;
|
||||
return;
|
||||
}
|
||||
|
||||
// 遍历文件
|
||||
QFileInfoList fileList = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
|
||||
for (const QFileInfo &fileInfo : fileList) {
|
||||
for (const QFileInfo &fileInfo : fileList)
|
||||
{
|
||||
QFile file(fileInfo.absoluteFilePath());
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
QString content = file.readAll();
|
||||
qDebug() << "读取文件 " << fileInfo.absoluteFilePath() << " 内容: " << content;
|
||||
file.close();
|
||||
// 写入文件操作示例:这里简单在文件末尾追加一行内容
|
||||
if (file.open(QIODevice::Append | QIODevice::Text)) {
|
||||
if (file.open(QIODevice::Append | QIODevice::Text))
|
||||
{
|
||||
file.write("\n这是通过递归写入添加的内容");
|
||||
qDebug() << "已向文件 " << fileInfo.absoluteFilePath() << " 写入内容";
|
||||
file.close();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "无法打开文件进行写入: " << fileInfo.absoluteFilePath();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "无法打开文件进行读取: " << fileInfo.absoluteFilePath();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void LeftWidget::slotTreeWidgetItemClicked(QTreeWidgetItem *item, int column) {
|
||||
void LeftWidget::slotTreeWidgetItemClicked(QTreeWidgetItem *item, int column)
|
||||
{
|
||||
qDebug() << "item clicked:" << item->text(0) << column;
|
||||
|
||||
if (Global::Mode::Analysis != Global::_mode) {
|
||||
if (Global::Mode::Analysis != Global::_mode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QString fileName;
|
||||
// 获取父节点
|
||||
QTreeWidgetItem *parentItem = item->parent();
|
||||
if (parentItem) {
|
||||
qDebug() << "parent item text:" << parentItem->text(0);
|
||||
if (parentItem == _sampleDataItem) {
|
||||
fileName = Global::SampleDataFloder + "/" + item->text(0);
|
||||
#if 0
|
||||
}else if(parentItem == _baseLineItem){
|
||||
fileName =Global::BaseLineFolder + "/" +item->text(0);
|
||||
#endif
|
||||
} else if (parentItem == _analysisStateItem) {
|
||||
fileName = Global::AnalysisStateFolder + "/" + item->text(0);
|
||||
}
|
||||
} else {
|
||||
qDebug() << "item has no parent (it is a top-level item)";
|
||||
// 检查是否是文件项(有用户数据)
|
||||
QVariant userData = item->data(0, Qt::UserRole);
|
||||
if (userData.isNull() || !userData.isValid())
|
||||
{
|
||||
qDebug() << "点击的是目录项或无效项";
|
||||
return;
|
||||
}
|
||||
|
||||
emit sigSendAnalysisFileName(fileName);
|
||||
QString filePath = userData.toString();
|
||||
if (filePath.isEmpty())
|
||||
{
|
||||
qDebug() << "文件路径为空";
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查文件是否存在
|
||||
QFileInfo fileInfo(filePath);
|
||||
if (!fileInfo.exists())
|
||||
{
|
||||
qWarning() << "文件不存在: " << filePath;
|
||||
return;
|
||||
}
|
||||
|
||||
// 发送文件路径信号
|
||||
emit sigSendAnalysisFileName(filePath);
|
||||
}
|
||||
void LeftWidget::initFileName(QTreeWidgetItem *parentItem, const QString &folderPath) {
|
||||
QDir dir(folderPath);
|
||||
|
||||
void LeftWidget::initFileName(QTreeWidgetItem *parentItem, const QString &folderPath)
|
||||
{
|
||||
QDir dir(folderPath);
|
||||
QStringList files = dir.entryList(QDir::Files);
|
||||
for (const QString &fileName : files) {
|
||||
for (const QString &fileName : files)
|
||||
{
|
||||
QTreeWidgetItem *subItem = new QTreeWidgetItem();
|
||||
subItem->setText(0, fileName);
|
||||
subItem->setData(0, Qt::UserRole, QVariant::fromValue(folderPath + "/" + fileName));
|
||||
@ -161,22 +180,25 @@ void LeftWidget::initFileName(QTreeWidgetItem *parentItem, const QString &folder
|
||||
}
|
||||
}
|
||||
|
||||
void LeftWidget::expandAll(QTreeWidgetItem *item) {
|
||||
void LeftWidget::expandAll(QTreeWidgetItem *item)
|
||||
{
|
||||
item->setExpanded(true);
|
||||
for (int i = 0; i < item->childCount(); ++i) {
|
||||
for (int i = 0; i < item->childCount(); ++i)
|
||||
{
|
||||
expandAll(item->child(i));
|
||||
}
|
||||
}
|
||||
|
||||
void LeftWidget::clearAllChildItems(QTreeWidgetItem *parentItem) {
|
||||
void LeftWidget::clearAllChildItems(QTreeWidgetItem *parentItem)
|
||||
{
|
||||
int childCount = parentItem->childCount();
|
||||
for (int i = 0; i < childCount; ++i) {
|
||||
for (int i = 0; i < childCount; ++i)
|
||||
{
|
||||
QTreeWidgetItem *childItem = parentItem->takeChild(0);
|
||||
delete childItem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void LeftWidget::recursiveFolderOperation(const QString& folderPath) {
|
||||
QDir dir(folderPath);
|
||||
@ -215,26 +237,334 @@ void LeftWidget::recursiveFolderOperation(const QString& folderPath) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void LeftWidget::slotShowContextMenu(const QPoint &pos) {
|
||||
QPoint globalPos = _treeWidget->mapToGlobal(pos);
|
||||
_contextMenu->exec(globalPos);
|
||||
|
||||
// 获取当前选中的项
|
||||
QTreeWidgetItem *currentItem = _treeWidget->itemAt(pos);
|
||||
if (currentItem == nullptr) {
|
||||
return;
|
||||
void LeftWidget::slotShowContextMenu(const QPoint &pos)
|
||||
{
|
||||
QTreeWidgetItem *item = _treeWidget->itemAt(pos);
|
||||
if (item) {
|
||||
// 获取文件路径
|
||||
QString filePath = item->data(0, Qt::UserRole).toString();
|
||||
QString dirPath = item->data(0, Qt::UserRole + 1).toString();
|
||||
|
||||
// 如果是文件
|
||||
if (!filePath.isEmpty()) {
|
||||
_deleteFileActionFilePath = filePath;
|
||||
_deleteFileAction->setVisible(true);
|
||||
_deleteFileAction->setText(tr("删除文件"));
|
||||
}
|
||||
// 如果是目录
|
||||
else if (!dirPath.isEmpty()) {
|
||||
// 暂时不要删除文件件功能
|
||||
_deleteFileAction->setVisible(false);
|
||||
#if 0
|
||||
_deleteFileAction->setVisible(true);
|
||||
_deleteFileActionFilePath = dirPath;
|
||||
_deleteFileAction->setText(tr("删除文件夹"));
|
||||
#endif
|
||||
} else {
|
||||
_deleteFileAction->setVisible(false);
|
||||
}
|
||||
|
||||
// 只有当点击的是目录时才显示"新建文件夹"选项
|
||||
bool isDir = !dirPath.isEmpty();
|
||||
_createFolderAction->setVisible(isDir);
|
||||
|
||||
_contextMenu->exec(_treeWidget->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
QString filePath = currentItem->data(0, Qt::UserRole).toString();
|
||||
if (filePath.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// qDebug() << "file:" << filePath;
|
||||
if (QFile::remove(filePath)) {
|
||||
qDebug() << "文件删除成功:" << filePath;
|
||||
} else {
|
||||
qWarning() << "文件删除失败:" << filePath;
|
||||
}
|
||||
|
||||
reloadFileName();
|
||||
}
|
||||
|
||||
void LeftWidget::slotDeleteActionTriggered()
|
||||
{
|
||||
if (_deleteFileActionFilePath.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFileInfo fileInfo(_deleteFileActionFilePath);
|
||||
bool isDir = fileInfo.isDir();
|
||||
|
||||
// 检查文件/目录是否存在
|
||||
if (!fileInfo.exists()) {
|
||||
QMessageBox::warning(this, tr("警告"), tr("文件/目录不存在!"));
|
||||
return;
|
||||
}
|
||||
|
||||
// 确认删除对话框
|
||||
int ret = QMessageBox::question(this, tr("确认删除"),
|
||||
tr("确定要删除%1\n%2?").arg(isDir ? tr("文件夹及其所有内容") : tr("文件")).arg(_deleteFileActionFilePath),
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::No);
|
||||
|
||||
if (ret == QMessageBox::Yes) {
|
||||
bool success;
|
||||
if (isDir) {
|
||||
// 删除目录及其内容
|
||||
success = removeDir(_deleteFileActionFilePath);
|
||||
} else {
|
||||
// 删除文件
|
||||
success = QFile::remove(_deleteFileActionFilePath);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
// 重新加载文件树
|
||||
reloadFileTree();
|
||||
} else {
|
||||
QMessageBox::critical(this, tr("错误"), tr("删除失败!"));
|
||||
}
|
||||
}
|
||||
|
||||
_deleteFileActionFilePath.clear();
|
||||
}
|
||||
|
||||
bool LeftWidget::removeDir(const QString &dirPath)
|
||||
{
|
||||
bool result = true;
|
||||
QDir dir(dirPath);
|
||||
|
||||
if (dir.exists(dirPath)) {
|
||||
Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) {
|
||||
if (info.isDir()) {
|
||||
result = removeDir(info.absoluteFilePath());
|
||||
} else {
|
||||
result = QFile::remove(info.absoluteFilePath());
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
result = dir.rmdir(dirPath);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void LeftWidget::slotCreateFolderActionTriggered()
|
||||
{
|
||||
// 获取当前选中的项目
|
||||
QTreeWidgetItem *currentItem = _treeWidget->currentItem();
|
||||
if (!currentItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取当前目录路径
|
||||
QString dirPath;
|
||||
if (currentItem->data(0, Qt::UserRole + 1).toString().isEmpty()) {
|
||||
// 如果是文件,获取其父目录
|
||||
dirPath = QFileInfo(currentItem->data(0, Qt::UserRole).toString()).absolutePath();
|
||||
} else {
|
||||
// 如果是目录,直接使用其路径
|
||||
dirPath = currentItem->data(0, Qt::UserRole + 1).toString();
|
||||
}
|
||||
|
||||
// 弹出对话框,输入新文件夹名称
|
||||
bool ok;
|
||||
QString folderName = QInputDialog::getText(this, tr("新建文件夹"),
|
||||
tr("请输入文件夹名称:"),
|
||||
QLineEdit::Normal,
|
||||
tr("新建文件夹"), &ok);
|
||||
|
||||
if (!ok || folderName.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查文件夹名称是否有效
|
||||
if (folderName.contains(QRegExp("[\\/:*?\"<>|]"))) {
|
||||
QMessageBox::warning(this, tr("错误"), tr("文件夹名称包含非法字符!"));
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建新文件夹路径
|
||||
QString newFolderPath = dirPath + "/" + folderName;
|
||||
|
||||
// 检查文件夹是否已存在
|
||||
if (QDir(newFolderPath).exists()) {
|
||||
QMessageBox::warning(this, tr("错误"), tr("文件夹已存在!"));
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建文件夹
|
||||
if (QDir().mkdir(newFolderPath)) {
|
||||
// 保存当前展开状态
|
||||
saveExpandedState();
|
||||
|
||||
// 重新加载文件树
|
||||
reloadFileTree();
|
||||
|
||||
// 恢复展开状态
|
||||
restoreExpandedState();
|
||||
|
||||
// 展开当前目录并选中新创建的文件夹
|
||||
expandAndSelectItem(newFolderPath);
|
||||
} else {
|
||||
QMessageBox::critical(this, tr("错误"), tr("创建文件夹失败!"));
|
||||
}
|
||||
}
|
||||
|
||||
void LeftWidget::expandAndSelectItem(const QString &path)
|
||||
{
|
||||
// 递归展开到指定路径并选中该项
|
||||
QTreeWidgetItemIterator it(_treeWidget);
|
||||
while (*it) {
|
||||
QTreeWidgetItem *item = *it;
|
||||
QString itemPath = item->data(0, Qt::UserRole + 1).toString();
|
||||
|
||||
if (itemPath == path) {
|
||||
// 展开所有父节点
|
||||
QTreeWidgetItem *parent = item->parent();
|
||||
while (parent) {
|
||||
parent->setExpanded(true);
|
||||
parent = parent->parent();
|
||||
}
|
||||
|
||||
// 选中新创建的文件夹
|
||||
_treeWidget->setCurrentItem(item);
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void LeftWidget::confirmDelete(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
if (QFile::remove(_deleteFileActionFilePath))
|
||||
{
|
||||
// qDebug() << "文件删除成功:" << filePath;
|
||||
logde << "delete succ:" << _deleteFileActionFilePath.toStdString();
|
||||
}
|
||||
else
|
||||
{
|
||||
// qWarning() << "文件删除失败:" << filePath;
|
||||
logde << "delete fail:" << _deleteFileActionFilePath.toStdString();
|
||||
}
|
||||
// 重新加载文件树
|
||||
reloadFileTree();
|
||||
}
|
||||
}
|
||||
|
||||
void LeftWidget::reloadFileTree()
|
||||
{
|
||||
// 保存当前展开状态
|
||||
saveExpandedState();
|
||||
|
||||
// 清空现有的树形结构
|
||||
_treeWidget->clear();
|
||||
|
||||
// 创建根节点
|
||||
QTreeWidgetItem *rootItem = new QTreeWidgetItem(_treeWidget);
|
||||
rootItem->setText(0, "实验数据");
|
||||
rootItem->setData(0, Qt::UserRole, Global::ExperimentDirPath);
|
||||
// 保存根目录路径,用于恢复展开状态
|
||||
rootItem->setData(0, Qt::UserRole + 1, Global::ExperimentDirPath);
|
||||
|
||||
// 递归扫描目录并构建树形结构
|
||||
buildFileTree(rootItem, Global::ExperimentDirPath);
|
||||
|
||||
// 展开根节点
|
||||
rootItem->setExpanded(true);
|
||||
|
||||
// 恢复展开状态
|
||||
restoreExpandedState();
|
||||
|
||||
// 更新全局文件列表
|
||||
Global::updateFileList();
|
||||
}
|
||||
|
||||
QFileInfoList LeftWidget::scanDirRecursively(const QString &rootPath)
|
||||
{
|
||||
QFileInfoList result; // 1. 结果容器
|
||||
QDirIterator it(rootPath, // 2. 迭代器:从 rootPath 开始
|
||||
QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, // 3. 要哪些条目
|
||||
QDirIterator::Subdirectories); // 4. 递归标志
|
||||
while (it.hasNext())
|
||||
{ // 5. 还有下一条吗?
|
||||
it.next(); // 6. 推进到下一个条目
|
||||
result.append(it.fileInfo()); // 7. 把当前条目塞进列表
|
||||
}
|
||||
return result; // 8. 返回
|
||||
}
|
||||
|
||||
void LeftWidget::buildFileTree(QTreeWidgetItem *parentItem, const QString &dirPath)
|
||||
{
|
||||
QDir dir(dirPath);
|
||||
if (!dir.exists()) {
|
||||
qWarning() << "目录不存在: " << dirPath;
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取所有子目录和文件,按名称排序
|
||||
dir.setSorting(QDir::Name | QDir::DirsFirst);
|
||||
QFileInfoList list = dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
|
||||
|
||||
for (const QFileInfo &fileInfo : list) {
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem(parentItem);
|
||||
|
||||
if (fileInfo.isDir()) {
|
||||
// 设置目录项
|
||||
item->setText(0, fileInfo.fileName());
|
||||
// 使用系统默认的目录图标
|
||||
item->setIcon(0, _treeWidget->style()->standardIcon(QStyle::SP_DirIcon));
|
||||
// 保存目录路径,用于恢复展开状态
|
||||
item->setData(0, Qt::UserRole + 1, fileInfo.absoluteFilePath());
|
||||
|
||||
// 递归处理子目录
|
||||
buildFileTree(item, fileInfo.absoluteFilePath());
|
||||
} else {
|
||||
// 设置文件项
|
||||
item->setText(0, fileInfo.fileName());
|
||||
item->setData(0, Qt::UserRole, fileInfo.absoluteFilePath());
|
||||
|
||||
// 根据文件类型设置不同的图标
|
||||
QString suffix = fileInfo.suffix().toLower();
|
||||
if (suffix == "xlsx" || suffix == "xls") {
|
||||
// 使用系统默认的文档图标
|
||||
item->setIcon(0, _treeWidget->style()->standardIcon(QStyle::SP_FileIcon));
|
||||
} else {
|
||||
// 使用默认文件图标
|
||||
item->setIcon(0, _treeWidget->style()->standardIcon(QStyle::SP_FileIcon));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LeftWidget::saveExpandedState()
|
||||
{
|
||||
_expandedPaths.clear();
|
||||
|
||||
// 递归遍历所有项,保存展开的目录路径
|
||||
QTreeWidgetItemIterator it(_treeWidget);
|
||||
while (*it) {
|
||||
QTreeWidgetItem *item = *it;
|
||||
if (item->isExpanded()) {
|
||||
QVariant pathData = item->data(0, Qt::UserRole + 1);
|
||||
if (!pathData.isNull()) {
|
||||
_expandedPaths.append(pathData.toString());
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
qDebug() << "保存了" << _expandedPaths.size() << "个展开状态:" << _expandedPaths;
|
||||
}
|
||||
|
||||
void LeftWidget::restoreExpandedState()
|
||||
{
|
||||
int restoredCount = 0;
|
||||
|
||||
// 递归遍历所有项,恢复展开状态
|
||||
QTreeWidgetItemIterator it(_treeWidget);
|
||||
while (*it) {
|
||||
QTreeWidgetItem *item = *it;
|
||||
QVariant pathData = item->data(0, Qt::UserRole + 1);
|
||||
if (!pathData.isNull()) {
|
||||
QString path = pathData.toString();
|
||||
if (_expandedPaths.contains(path)) {
|
||||
item->setExpanded(true);
|
||||
restoredCount++;
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
qDebug() << "恢复了" << restoredCount << "个展开状态";
|
||||
}
|
||||
|
||||
@ -19,18 +19,30 @@ public:
|
||||
|
||||
void reloadFileName();
|
||||
|
||||
void reloadFileTree();
|
||||
|
||||
QString filePathCheck(const QString fileName,const QString folderPath);
|
||||
// 确认删除文件
|
||||
void confirmDelete(bool enabled);
|
||||
signals:
|
||||
void sigSendAnalysisFileName(const QString&);
|
||||
void sigDeleteActionTriggered(const QString&);
|
||||
private:
|
||||
void initData();
|
||||
void initFileName(QTreeWidgetItem*,const QString &folderPath);
|
||||
void expandAll(QTreeWidgetItem* item);
|
||||
void clearAllChildItems(QTreeWidgetItem* parentItem);
|
||||
void removeFile(const QString& filePath);
|
||||
QFileInfoList scanDirRecursively(const QString &rootPath);
|
||||
void buildFileTree(QTreeWidgetItem *parentItem, const QString &dirPath);
|
||||
void saveExpandedState();
|
||||
void restoreExpandedState();
|
||||
void expandAndSelectItem(const QString &path);
|
||||
bool removeDir(const QString &dirPath);
|
||||
private slots:
|
||||
void slotTreeWidgetItemClicked(QTreeWidgetItem *item, int column);
|
||||
void slotShowContextMenu(const QPoint &pos);
|
||||
void slotDeleteActionTriggered();
|
||||
void slotCreateFolderActionTriggered();
|
||||
private:
|
||||
QTreeWidget *_treeWidget;
|
||||
|
||||
@ -39,7 +51,14 @@ private:
|
||||
*_sampleDataItem;
|
||||
|
||||
QMenu *_contextMenu;
|
||||
QAction *_deleteAction;
|
||||
|
||||
QAction *_deleteFileAction;
|
||||
QAction *_createFolderAction;
|
||||
QString _deleteFileActionFilePath;
|
||||
|
||||
// 保存展开状态的列表
|
||||
QStringList _expandedPaths;
|
||||
};
|
||||
|
||||
#endif // LEFTWIDGET_H
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user