From 370c869ad0ba59c0ba84c67e8da0bd4a85a6727f Mon Sep 17 00:00:00 2001 From: Wang Zichong Date: Mon, 12 Oct 2026 17:18:16 +0800 Subject: [PATCH] feat(gui): add an Apply button for live preview of settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split applying settings from closing the dialog, so appearance changes (opacity, font size, line counts) can be previewed without dismissing it. The caption window now listens to settingsApplied and updates immediately; only model, language or capture-device changes restart the ASR backend. 设置对话框新增「应用」按钮:应用设置但不关闭对话框,方便实时预览(不透明度、 字号等立刻可见)。字幕窗改为监听 settingsApplied 即时更新;只有模型/识别语言/ 采集设备变化才重启识别后端,外观调整不会打断正在进行的转写。 --- apps/gui/main.cpp | 48 ++++++++++++++++++++++++++++----------- docs/asr-backends.md | 10 ++++++++ src/ui/settingsdialog.cpp | 25 ++++++++++++++++---- src/ui/settingsdialog.h | 4 +++- 4 files changed, 68 insertions(+), 19 deletions(-) diff --git a/apps/gui/main.cpp b/apps/gui/main.cpp index 30d4518..ac857bf 100644 --- a/apps/gui/main.cpp +++ b/apps/gui/main.cpp @@ -131,6 +131,16 @@ int main(int argc, char ** argv) if (b->text() == QObject::tr("确定")) { b->click(); break; } } } + else if (autoclose == QLatin1String("apply")) { // 点「应用」,应保持打开 + for (auto * b : dlg.findChildren()) { + if (b->text() == QObject::tr("应用")) { b->click(); break; } + } + QTimer::singleShot(400, &dlg, [&dlg] { + std::fprintf(stderr, "点「应用」后对话框仍可见: %s\n", + dlg.isVisible() ? "是 ✅" : "否 ❌"); + dlg.reject(); + }); + } }); }; @@ -197,17 +207,35 @@ int main(int argc, char ** argv) qWarning("采集失败: %s", qUtf8Printable(m)); }); - // 语言 pill → 设置 - QObject::connect(&window, &lc::CaptionWindow::languageClicked, &window, [&] { + // 后端相关项(模型/语言/采集设备)变化才需要重启;外观类改动即时生效 + const auto backendKey = [&cfg] { + return cfg.modelId + QLatin1Char('|') + cfg.language + QLatin1Char('|') + cfg.captureDevice; + }; + QString activeKey = backendKey(); + + const auto openSettings = [&] { lc::SettingsDialog dlg(false); + QObject::connect(&dlg, &lc::SettingsDialog::settingsApplied, &window, [&] { + applyAppearance(window, cfg); // 透明度/字号等立刻可见 + if (backendKey() != activeKey) { + if (startTranscriber()) activeKey = backendKey(); + } + }); if (dlg.exec() == QDialog::Accepted) { applyAppearance(window, cfg); - if (!startTranscriber()) { - QMessageBox::warning(&window, QObject::tr("启动失败"), - QObject::tr("模型加载失败,请检查设置。")); + if (backendKey() != activeKey) { + if (!startTranscriber()) { + QMessageBox::warning(&window, QObject::tr("启动失败"), + QObject::tr("模型加载失败,请检查设置。")); + } else { + activeKey = backendKey(); + } } } - }); + }; + + // 语言 pill → 设置 + QObject::connect(&window, &lc::CaptionWindow::languageClicked, &window, openSettings); // ---- 托盘 ---- QSystemTrayIcon * tray = nullptr; @@ -224,13 +252,7 @@ int main(int argc, char ** argv) QObject::connect(showAct, &QAction::triggered, &window, [&window] { window.setVisible(!window.isVisible()); }); - QObject::connect(setAct, &QAction::triggered, &window, [&] { - lc::SettingsDialog dlg(false); - if (dlg.exec() == QDialog::Accepted) { - applyAppearance(window, cfg); - startTranscriber(); - } - }); + QObject::connect(setAct, &QAction::triggered, &window, openSettings); QObject::connect(quitAct, &QAction::triggered, &app, &QApplication::quit); QObject::connect(tray, &QSystemTrayIcon::activated, &window, [&window](QSystemTrayIcon::ActivationReason r) { diff --git a/docs/asr-backends.md b/docs/asr-backends.md index 04c7c9d..c0678f9 100644 --- a/docs/asr-backends.md +++ b/docs/asr-backends.md @@ -63,6 +63,16 @@ IAsr(src/core/iasr.h) > 同步/自旋开销会让它更慢(8 线程比 1 线程慢 2.6 倍、CPU 高 28 倍)。所以适配器里固定 > `threads = 1`。 +## 设置对话框 + +三个页签(模型 / 显示 / 高级),底部三个按钮: + +- **应用**:应用设置但**不关闭**对话框,方便实时预览(改不透明度、字号时会立刻看到效果); +- **取消**:放弃本次改动; +- **确定**:应用并关闭。 + +只有**模型 / 识别语言 / 采集设备**变化才会重启识别后端;透明度、字号、行数、位置这类外观改动是即时生效的,不会打断正在进行的转写。 + ## 采集设备选择 默认跟随系统默认输出;也可以在设置里指定某个输出设备(`--list-devices` 可列出): diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 6de4ef3..10ec1d4 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -54,15 +54,18 @@ SettingsDialog::SettingsDialog(bool firstRun, QWidget * parent) : QString()); auto * okBtn = new QPushButton(tr("确定"), this); + auto * applyBtn = new QPushButton(tr("应用"), this); auto * cancelBtn = new QPushButton(tr("取消"), this); okBtn->setDefault(true); - connect(okBtn, &QPushButton::clicked, this, [this] { - if (ensureModelSelected()) onApply(); - }); + okBtn->setToolTip(tr("应用并关闭")); + applyBtn->setToolTip(tr("应用但不关闭,方便预览效果")); + connect(okBtn, &QPushButton::clicked, this, &SettingsDialog::onAccept); + connect(applyBtn, &QPushButton::clicked, this, &SettingsDialog::onApplyClicked); connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject); auto * buttons = new QHBoxLayout; buttons->addStretch(1); + buttons->addWidget(applyBtn); buttons->addWidget(cancelBtn); buttons->addWidget(okBtn); @@ -440,7 +443,20 @@ bool SettingsDialog::ensureModelSelected() return true; } -void SettingsDialog::onApply() +void SettingsDialog::onAccept() +{ + if (ensureModelSelected()) { + applySettings(); + accept(); + } +} + +void SettingsDialog::onApplyClicked() +{ + if (ensureModelSelected()) applySettings(); +} + +void SettingsDialog::applySettings() { AppSettings & cfg = AppSettings::instance(); cfg.mirrorBase = mirrorEdit_->text().trimmed(); @@ -469,7 +485,6 @@ void SettingsDialog::onApply() } cfg.save(); Q_EMIT settingsApplied(); - accept(); } } // namespace lc diff --git a/src/ui/settingsdialog.h b/src/ui/settingsdialog.h index 3ddff85..79ce810 100644 --- a/src/ui/settingsdialog.h +++ b/src/ui/settingsdialog.h @@ -41,7 +41,9 @@ private: void onVerify(); void onDelete(); void onOpenDir(); - void onApply(); + void applySettings(); // 读取控件 → 保存 → 发 settingsApplied(不关闭对话框) + void onAccept(); // 确定:applySettings + 关闭 + void onApplyClicked(); // 应用:只 applySettings bool ensureModelSelected(); QTableWidget * table_ = nullptr;