2025-12-11T16:15:35

This commit is contained in:
yuntang 2025-12-11 16:15:36 +08:00
parent 8e3c534710
commit 0583d5f84f
18 changed files with 851 additions and 293 deletions

26
.vscode/settings.json vendored Normal file
View 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"
}
}

View 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.

View File

@ -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"
}
]
}

View File

@ -9,7 +9,7 @@ CONFIG+=precompile_header
PRECOMPILED_HEADER=stable.h
#
VERSION = 1.3.7
VERSION = 1.4.0
# 设置目标文件名,包含版本号
TARGET = DSCAnalysisTool_$${VERSION}

View File

@ -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()

View File

@ -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);
}

View File

@ -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();

View File

@ -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 << "个展开状态";
}

View File

@ -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