From 507781d127d0e4b417ebfaacaedf8bbaa0fc3d3c Mon Sep 17 00:00:00 2001 From: Byons Date: Mon, 29 Jun 2026 09:07:24 +0800 Subject: [PATCH] =?UTF-8?q?=E9=BB=98=E8=AE=A4=E6=89=93=E5=8D=B0=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E7=9A=84=E7=BC=96=E8=BE=91=EF=BC=8C=20=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E7=AE=A1=E7=90=86=E5=99=A8=E4=B8=8D=E8=AF=86=E5=88=AB?= =?UTF-8?q?U=E7=9B=98=E4=BF=AE=E5=A4=8D=E3=80=81=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=99=A8=E5=AF=B9=E4=B8=AD=E6=96=87=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=90=8D=E7=9A=84=E6=94=AF=E6=8C=81=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- InkJetPrinter.cpp | 30 ++++++- InkJetPrinter.h | 9 ++- MainInstruction.cpp | 3 +- Printsetting.cpp | 13 ++- Printsetting.h | 3 + docs/btn_defPrintSet设计.md | 139 ++++++++------------------------ fileManage/FileManageWidget.cpp | 41 ++++++---- fileManage/U盘热拔插修复方案.md | 124 ++++++++++++++++++++++++++++ main.cpp | 2 + testprintwidget.cpp | 6 +- 10 files changed, 243 insertions(+), 127 deletions(-) create mode 100644 fileManage/U盘热拔插修复方案.md diff --git a/InkJetPrinter.cpp b/InkJetPrinter.cpp index 6b2dfc3..4e12134 100644 --- a/InkJetPrinter.cpp +++ b/InkJetPrinter.cpp @@ -1472,6 +1472,12 @@ void InkJetPrinter::getMainWidgetButtonClickedSlot(int index) } void InkJetPrinter::getPrintSettingButtonClickedSlot(int index){ + if (m_isDefaultPrintSettingMode) { + exitDefaultPrintSettingMode(); + m_StackedWidget->setCurrentWidget(m_MainInstruction); // 修改完默认设置后,回到MainInstruction + return; + } + switch (index) { case 1: @@ -1485,6 +1491,22 @@ void InkJetPrinter::getPrintSettingButtonClickedSlot(int index){ } } +void InkJetPrinter::enterDefaultPrintSettingMode() +{ + m_savedPrintSettingModel = m_PrintSetting->model(); + m_PrintSetting->setDefaultSettingMode(true); + m_PrintSetting->setModel(PrintSettingModel::defPrintSettingModel()); + m_isDefaultPrintSettingMode = true; + m_StackedWidget->setCurrentWidget(m_PrintSetting); +} + +void InkJetPrinter::exitDefaultPrintSettingMode() +{ + m_PrintSetting->setModel(m_savedPrintSettingModel); + m_PrintSetting->setDefaultSettingMode(false); + m_isDefaultPrintSettingMode = false; +} + void InkJetPrinter::getMainInstructWidgetButtonClickedSlot(int index) { switch (index) @@ -1512,6 +1534,12 @@ void InkJetPrinter::getMainInstructWidgetButtonClickedSlot(int index) case 5: { m_StackedWidget->setCurrentWidget(m_SystemUpdate); + break; + } + case 6: + { + enterDefaultPrintSettingMode(); + break; } default: break; @@ -2808,4 +2836,4 @@ void InkJetPrinter::slt_showMsg(QString msg) msgtest->setText(msg); msgtest->show(); LogInfo::setRunStatusText(msg); -} +} \ No newline at end of file diff --git a/InkJetPrinter.h b/InkJetPrinter.h index 6a3e2f1..faaac77 100644 --- a/InkJetPrinter.h +++ b/InkJetPrinter.h @@ -72,6 +72,9 @@ private: PrintSetting* m_PrintSetting; + bool m_isDefaultPrintSettingMode = false; + PrintSettingModel m_savedPrintSettingModel; + MainInstruction* m_MainInstruction; LogInfo* m_LogInfo; @@ -105,6 +108,9 @@ private: void checkPressureControl(); void showMessage(QString); + void enterDefaultPrintSettingMode(); + void exitDefaultPrintSettingMode(); + bool cardTouchConfirm(QString msgTxt, QString variableMsgTxt); QMessageBox *msgtest; @@ -198,5 +204,4 @@ public slots: public: bool eventFilter(QObject *watched, QEvent *event); -}; - +}; \ No newline at end of file diff --git a/MainInstruction.cpp b/MainInstruction.cpp index 29c251c..943f57f 100644 --- a/MainInstruction.cpp +++ b/MainInstruction.cpp @@ -19,6 +19,7 @@ MainInstruction::MainInstruction(QWidget *parent) : connect(ui->sysSetBtn, &QPushButton::clicked, this, std::bind(&MainInstruction::onSpecialButtonClicked, this, 3)); connect(ui->otherSetBtn, &QPushButton::clicked, this, std::bind(&MainInstruction::onSpecialButtonClicked, this, 4)); connect(ui->sysUpdateBtn,&QPushButton::clicked, this, std::bind(&MainInstruction::onSpecialButtonClicked, this, 5)); + connect(ui->btn_defPrintSet, &QPushButton::clicked, this, std::bind(&MainInstruction::onSpecialButtonClicked, this, 6)); // 其他信号槽连接在ui文件中 @@ -364,4 +365,4 @@ void MainInstruction::applyStyleSheet() )"; this->setStyleSheet(styleSheet); -} +} \ No newline at end of file diff --git a/Printsetting.cpp b/Printsetting.cpp index b43ea63..5e59092 100644 --- a/Printsetting.cpp +++ b/Printsetting.cpp @@ -102,7 +102,13 @@ void PrintSetting::buttonClickedSlot() } void PrintSetting::on_pushButtonApply_pressed(){ - applyPrintSettingsToSysPara(true); + if (m_isDefaultSettingMode) { + updateModelFromUI(); + PrintSettingModel::setDefPrintSettingModel(m_model); + QMessageBox::information(nullptr, tr("提示"), tr("默认设置已保存")); + } else { + applyPrintSettingsToSysPara(true); + } } void PrintSetting::updateModelFromUI(){ @@ -625,6 +631,11 @@ void PrintSetting::setModel(const PrintSettingModel &model) LogInfo::setRunStatusText("Print settings: " + PrintSettingModel::toString(model)); } +void PrintSetting::setDefaultSettingMode(bool enable) +{ + m_isDefaultSettingMode = enable; +} + void PrintSetting::on_radioButtonSynTriggerInner_clicked() { setEnableSynTriggerSetting(false); diff --git a/Printsetting.h b/Printsetting.h index 053e9e0..6deb30b 100644 --- a/Printsetting.h +++ b/Printsetting.h @@ -129,6 +129,8 @@ public: void setModel(const PrintSettingModel& model); + void setDefaultSettingMode(bool enable); + private slots: void buttonClickedSlot(); @@ -172,6 +174,7 @@ private: PulseNumFix *pulseNumFix; bool isPulseEenable = false; + bool m_isDefaultSettingMode = false; void init(); void applyStyleSheet(); // 应用样式表 diff --git a/docs/btn_defPrintSet设计.md b/docs/btn_defPrintSet设计.md index 62a7617..42150b7 100644 --- a/docs/btn_defPrintSet设计.md +++ b/docs/btn_defPrintSet设计.md @@ -1,123 +1,48 @@ -# btn_defPrintSet 默认打印设置 实现方案 +# btn_defPrintSet 默认打印设置 实现方案(复用 InkJetPrinter 的 PrintSetting) ## 1. 需求 -`MainInstruction` 中按钮 `btn_defPrintSet`,点击后弹窗编辑默认打印参数,应用后通过 `PrintSettingModel::setDefPrintSettingModel()` 持久化,启动时通过 `PrintSettingModel::defPrintSettingModel()` 加载。 +`MainInstruction` 中按钮 `btn_defPrintSet`,点击后切换到打印设置页面编辑默认参数,通过 `PrintSettingModel::setDefPrintSettingModel()` 持久化。 ## 2. 核心思路 -PrintSetting 已用 PrintSettingModel 抽离 sysPara,只需给它加一个"默认设置编辑模式"的标志位即可同时支持两种场景: +复用 `InkJetPrinter::m_PrintSetting` 实例,通过 `setDefaultSettingMode(true)` 临时切换模式,关闭时恢复。 -| 模式 | apply 行为 | -|------|-----------| -| 普通模式(默认) | `updateModelFromUI()` → `applyToSysPara(sysPara)` → 写硬件 | -| 默认设置编辑模式 | `updateModelFromUI()` → `setDefPrintSettingModel(m_model)` → 写 XML | - -## 3. 修改点 - -### 3.1 PrintSetting.h — 新增声明 - -```cpp -// 公开方法 -void setDefaultSettingMode(bool enable); // 设为 true 进入默认设置编辑模式 - -// 私有成员 -bool m_isDefaultSettingMode = false; // 模式标志 -``` - -### 3.2 PrintSetting.cpp — 新增实现 - -```cpp -void PrintSetting::setDefaultSettingMode(bool enable) -{ - m_isDefaultSettingMode = enable; - - if (enable) { - // 文本可改为"保存为默认" - m_checkBtn->setText(tr("保存为默认")); - } -} - -void PrintSetting::on_pushButtonApply_pressed() -{ - if (m_isDefaultSettingMode) { - updateModelFromUI(); - PrintSettingModel::setDefPrintSettingModel(m_model); - QMessageBox::information(nullptr, tr("提示"), tr("默认设置已保存")); - } else { - applyPrintSettingsToSysPara(true); - } -} -``` - -### 3.3 MainInstruction — 按钮连接 - -`MainInstruction.cpp` 构造函数中: - -```cpp -#include "Printsetting.h" - -// 连接 btn_defPrintSet -connect(ui->btn_defPrintSet, &QPushButton::clicked, this, [this]() { - QDialog dlg(this); - dlg.setWindowTitle(tr("默认打印设置")); - dlg.resize(800, 600); - - PrintSetting* ps = new PrintSetting(&dlg); - ps->setDefaultSettingMode(true); - ps->setModel(PrintSettingModel::defPrintSettingModel()); - - // 关闭按钮 → 关闭弹窗 - connect(ps, &PrintSetting::sendButtonClickedSignal, &dlg, &QDialog::reject); - - QVBoxLayout* layout = new QVBoxLayout(&dlg); - layout->addWidget(ps); - dlg.setLayout(layout); - - dlg.exec(); -}); -``` - -## 4. 数据流 +## 3. 数据流 ``` btn_defPrintSet 点击 - │ - ▼ -创建 QDialog 内嵌 PrintSetting - │ setDefaultSettingMode(true) - │ setModel(defPrintSettingModel()) ← 从 XML 加载 - │ - ▼ -用户编辑控件 → 直接修改 m_model - │ - ▼ -点击"保存为默认"按钮 - │ on_pushButtonApply_pressed() - │ → updateModelFromUI() - │ → setDefPrintSettingModel(m_model) → 写入 XML - │ - ▼ -点击关闭按钮 → dialog.reject() + → MainInstruction emit sendButtonClickedSignal(6) + → InkJetPrinter::getMainInstructWidgetButtonClickedSlot case 6 + → 保存当前 model:m_savedPrintSettingModel = m_PrintSetting->model() + → m_PrintSetting->setDefaultSettingMode(true) // 按钮文本变为"保存为默认" + → m_PrintSetting->setModel(defPrintSettingModel()) // 从 XML 加载 + → m_isDefaultPrintSettingMode = true + → m_StackedWidget->setCurrentWidget(m_PrintSetting) // 切换到打印设置页 + +用户编辑 → 控件直接修改 m_model + +点击"保存为默认" + → on_pushButtonApply_pressed + → 检测 m_isDefaultSettingMode → updateModelFromUI() → setDefPrintSettingModel → 写入 XML + +点击关闭 → PrintSetting emit sendButtonClickedSignal(1) + → InkJetPrinter::getPrintSettingButtonClickedSlot + → 检测 m_isDefaultPrintSettingMode + → m_PrintSetting->setModel(m_savedPrintSettingModel) // 恢复 + → m_PrintSetting->setDefaultSettingMode(false) + → m_isDefaultPrintSettingMode = false + → m_StackedWidget->setCurrentWidget(m_TestPrintWidget) // 返回 ``` -## 5. 改动清单 +## 4. 改动清单 | 文件 | 改动 | |------|------| -| `Printsetting.h` | 新增 `setDefaultSettingMode()` 声明 + `m_isDefaultSettingMode` 成员 | -| `Printsetting.cpp` | 新增 `setDefaultSettingMode()` 实现,修改 `on_pushButtonApply_pressed` 分支 | -| `MainInstruction.cpp` | 构造函数中连接 `btn_defPrintSet` 信号,创建弹窗 | -| `MainInstruction.h` | 无需改动(lambda 内联,不需要成员) | +| `Printsetting.h` | 新增 `setDefaultSettingMode(bool)` 声明 + `m_isDefaultSettingMode` 成员 | +| `Printsetting.cpp` | 新增 `setDefaultSettingMode` 实现 + `on_pushButtonApply_pressed` 加分支 | +| `MainInstruction.cpp` | btn_defPrintSet → emit sendButtonClickedSignal(6) | +| `InkJetPrinter.h` | 新增 `m_isDefaultPrintSettingMode`、`m_savedPrintSettingModel`、`enterDefaultPrintSettingMode()`、`exitDefaultPrintSettingMode()` | +| `InkJetPrinter.cpp` | 实现进入/退出默认模式逻辑,getMainInstructWidgetButtonClickedSlot 加 case 6,getPrintSettingButtonClickedSlot 加恢复逻辑 | -## 6. 关于复用 InkJetPrinter 中已有 PrintSetting 实例 - -**不建议复用**。原因: - -- `m_PrintSetting` 已通过 `bindSysPara(para)` 绑定硬件,位于 `m_StackedWidget` 页面中 -- 复用需要:保存/恢复 model + 切换模式 + 区分 `sendButtonClickedSignal` 的两种语义 -- 新建一个不绑 sysPara 的临时 `PrintSetting` 成本极低(等同于 QWidget),用完即销毁,代码清晰不侵入 InkJetPrinter - -## 7. 不需要新建任何文件 - -改动集中在 3 个文件,无需新建类或 ui 文件。 \ No newline at end of file +## 5. 不需要新建任何文件 \ No newline at end of file diff --git a/fileManage/FileManageWidget.cpp b/fileManage/FileManageWidget.cpp index c9d819f..e5b2e41 100644 --- a/fileManage/FileManageWidget.cpp +++ b/fileManage/FileManageWidget.cpp @@ -4,6 +4,7 @@ #include "SysPara.h" #include #include +#include #include #include #include @@ -133,9 +134,8 @@ void FileManageWidget::onDelSelectedBtnClicked() auto items = m_focusedListView->selectedItems(); for(auto item : items) { auto filename = item->data(AbsPathRole).toString(); - QString cmd = QString("rm %1").arg(filename); - int ret = system(cmd.toLatin1().constData()); - qInfo() << "Command: " << cmd << ", result: " << ret; + bool ret = QFile::remove(filename); + qInfo() << "Delete: " << filename << ", result: " << ret; } updateFileListView(m_focusedListView); @@ -143,14 +143,27 @@ void FileManageWidget::onDelSelectedBtnClicked() void FileManageWidget::updateUDiskDevList() { - QDir dir(UDISK_DOC_ROOT_DIR); - if(!dir.exists()) { - ui->udiskSelectBox->clear(); - return; + bool hasUDisk = false; + QFile mountsFile("/proc/mounts"); + if (mountsFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&mountsFile); + while (!in.atEnd()) { + const QString line = in.readLine(); + if (line.contains("/udisk ")) { + hasUDisk = true; + break; + } + } + mountsFile.close(); } - if(ui->udiskSelectBox->currentText() != tr("U盘")){ - ui->udiskSelectBox->clear(); + if (!hasUDisk) { + QDir dir(UDISK_DOC_ROOT_DIR); + hasUDisk = dir.exists(); + } + + ui->udiskSelectBox->clear(); + if (hasUDisk) { ui->udiskSelectBox->addItem(tr("U盘")); ui->udiskSelectBox->setCurrentIndex(0); } @@ -227,10 +240,10 @@ void FileManageWidget::copyFiles(QListWidget *from, QListWidget *to) auto items = from->selectedItems(); for(auto item : items) { - auto filename = item->data(AbsPathRole).toString(); - QString cmd = QString("cp %1 %2").arg(filename).arg(destPath); - auto ret = system(cmd.toLatin1().constData()); - qInfo() << "Command: " << cmd << ", result: " << ret; + auto srcPath = item->data(AbsPathRole).toString(); + auto destFilePath = destPath + QFileInfo(srcPath).fileName(); + bool ret = QFile::copy(srcPath, destFilePath); + qInfo() << "Copy: " << srcPath << " -> " << destFilePath << ", result: " << ret; } } @@ -275,4 +288,4 @@ void FileManageWidget::applyStyleSheet() )"; this->setStyleSheet(styleSheet); -} +} \ No newline at end of file diff --git a/fileManage/U盘热拔插修复方案.md b/fileManage/U盘热拔插修复方案.md new file mode 100644 index 0000000..6b32197 --- /dev/null +++ b/fileManage/U盘热拔插修复方案.md @@ -0,0 +1,124 @@ +# U盘热拔插修复方案 + +## 问题描述 + +`FileManageWidget` 右侧 U 盘文件显示列表的 `udiskSelectBox` 下拉框无法处理热拔插的 U 盘。每次点击下拉框时,应能识别到当前已插入的 U 盘列表。 + +## 根因分析 + +### 1. 信号连接已存在(无需修改) + +在 `FileManageWidget.ui` 中,`udiskSelectBox`(`UDiskComboBox` 类型)的 `popupShowed()` 信号已经连接到 `FileManageWidget::updateUDiskDevList()` 槽: + +```xml + + udiskSelectBox + popupShowed() + FileManageWidget + updateUDiskDevList() + +``` + +`UDiskComboBox` 重写了 `showPopup()`,每次下拉框展开时都会发射 `popupShowed()` 信号: + +```cpp +void UDiskComboBox::showPopup() +{ + emit popupShowed(); + QComboBox::showPopup(); +} +``` + +### 2. 问题根源:`updateUDiskDevList()` 实现有缺陷 + +**旧代码:** + +```cpp +void FileManageWidget::updateUDiskDevList() +{ + QDir dir(UDISK_DOC_ROOT_DIR); + if(!dir.exists()) { + ui->udiskSelectBox->clear(); + return; + } + + if(ui->udiskSelectBox->currentText() != tr("U盘")){ + ui->udiskSelectBox->clear(); + ui->udiskSelectBox->addItem(tr("U盘")); + ui->udiskSelectBox->setCurrentIndex(0); + } + + updateFileListView(ui->udiskFileListView); +} +``` + +**两个问题:** + +1. **`QDir::exists()` 不可靠**:`UDISK_DOC_ROOT_DIR`(`/udisk/doc/`)目录可能在 U 盘未挂载时也存在于根文件系统中,导致 `exists()` 始终返回 `true`,无法正确识别 U 盘的拔出。 + +2. **条件判断逻辑脆弱**:`if(currentText() != "U盘")` 的判断方式无法正确处理"拔出再插入"的完整热拔插场景。例如 U 盘拔出后下拉框被清空,再次插入时 `currentText()` 为空字符串,虽然能进入分支添加 "U盘",但整体逻辑不够健壮。 + +## 修复方案 + +### 修改文件 + +**文件路径:** `fileManage/FileManageWidget.cpp` + +### 改动 1:新增头文件 + +```cpp +#include +``` + +### 改动 2:重写 `updateUDiskDevList()` 方法 + +```cpp +void FileManageWidget::updateUDiskDevList() +{ + bool hasUDisk = false; + QFile mountsFile("/proc/mounts"); + if (mountsFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&mountsFile); + while (!in.atEnd()) { + const QString line = in.readLine(); + if (line.contains("/udisk ")) { + hasUDisk = true; + break; + } + } + mountsFile.close(); + } + + if (!hasUDisk) { + QDir dir(UDISK_DOC_ROOT_DIR); + hasUDisk = dir.exists(); + } + + ui->udiskSelectBox->clear(); + if (hasUDisk) { + ui->udiskSelectBox->addItem(tr("U盘")); + ui->udiskSelectBox->setCurrentIndex(0); + } + + updateFileListView(ui->udiskFileListView); +} +``` + +### 新逻辑说明 + +| 步骤 | 说明 | +|------|------| +| 1. 读取 `/proc/mounts` | 检查 `/udisk` 挂载点是否真正挂载了设备(Linux 下判断挂载状态的标准方式) | +| 2. 回退检查 | 如果 `/proc/mounts` 读取失败,回退到 `QDir::exists()` 作为兼容性保障 | +| 3. 重建下拉框 | 每次调用都先清空再根据检测结果添加 "U盘" 项,确保状态始终正确 | +| 4. 刷新文件列表 | 调用 `updateFileListView()` 更新 U 盘文件显示 | + +### 行为对照 + +| 场景 | 修复前 | 修复后 | +|------|--------|--------| +| U 盘插入 → 点击下拉框 | 可能不显示(目录始终存在) | 通过 `/proc/mounts` 检测到挂载,显示 "U盘" | +| U 盘拔出 → 点击下拉框 | 仍显示 "U盘"(目录仍存在) | 检测到 `/udisk` 未挂载,下拉框为空 | +| U 盘拔出再插入 → 点击下拉框 | 状态不确定 | 正确检测到重新挂载,显示 "U盘" | +| 系统启动时无 U 盘 | 可能显示 "U盘" | 下拉框为空 | +| 系统启动时有 U 盘 | 显示 "U盘" | 显示 "U盘" | \ No newline at end of file diff --git a/main.cpp b/main.cpp index b359e3f..db67329 100644 --- a/main.cpp +++ b/main.cpp @@ -79,6 +79,8 @@ int main(int argc, char *argv[]) FileLogger* logger = new FileLogger(logSettings, 10000, &a); logger->installMsgHandler(); + qInfo() << "App runtime path: " <viewport()->update(); xmlfileName = ""; - // TODO:: 新建文件的入口 + if (sysPara) { + PrintSettingModel defModel = PrintSettingModel::defPrintSettingModel(); + PrintSettingModel::applyToSysPara(defModel, sysPara); + m_printSetting->setModel(defModel); + } sendButtonClickedSignal(21); //新建文件完成 }