// ============================================================================ // qdialog_showcase —— QDialog 教学综合示例 // 参考川大 wiki「6 对话框 QDialog」(pageId 183664881) 的 6.2–6.5: // 6.3 模态/非模态(exec / open / show + WA_DeleteOnClose) // 6.4 QMessageBox(六个 static + 实例 API) // 6.2/6.5 标准对话框(QFileDialog / QColorDialog / QFontDialog / QInputDialog) // 形态:一个 QWidget 布满 pushbutton,每个按钮触发一种 QDialog 行为。 // 纯代码(无 .ui);主类不定义信号槽,全部用 lambda 连接 QPushButton::clicked。 // ============================================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dialog.h" class DialogShowcase : public QWidget { public: explicit DialogShowcase(QWidget *parent = nullptr) : QWidget(parent) { auto *root = new QVBoxLayout(this); // 反馈标签:显示标准对话框 / question 的返回值 statusLabel = new QLabel(QStringLiteral("点击下方按钮,体验不同的 QDialog 行为。")); statusLabel->setWordWrap(true); statusLabel->setMinimumHeight(36); // ① 模态/非模态(6.3) ------------------------------------------------- auto *g1 = new QGroupBox(QStringLiteral("① 模态/非模态(6.3)")); auto *l1 = new QGridLayout(g1); addBtn(l1, 0, 0, QStringLiteral("模态 exec"), [this] { QDialog d(this); d.setWindowTitle(QStringLiteral("模态对话框(exec)")); d.exec(); // 应用级模态:阻塞整个应用,直到关闭 setStatus(QStringLiteral("exec() 返回 —— 应用级模态已关闭")); }); addBtn(l1, 0, 1, QStringLiteral("窗口模态 open"), [this] { auto *d = new QDialog(this); d->setWindowTitle(QStringLiteral("窗口级模态(open)")); d->setAttribute(Qt::WA_DeleteOnClose); d->open(); // 窗口级模态:仅阻塞父窗口,其余窗口仍可交互 setStatus(QStringLiteral("open() 弹出窗口级模态(仅阻塞父窗口)")); }); addBtn(l1, 1, 0, QStringLiteral("非模态 show"), [this] { // 必须用堆对象:栈对象在 show() 返回后随作用域结束而析构,对话框一闪而过 // (页面 6.3 强调的坑)。这里给 parent this,由 Qt 对象树托管生命周期。 auto *d = new QDialog(this); d->setWindowTitle(QStringLiteral("非模态对话框(show)")); d->show(); // 非模态:立即返回、不阻塞,可与主窗口同时操作 setStatus(QStringLiteral("show() 非模态弹出(不阻塞)")); }); addBtn(l1, 1, 1, QStringLiteral("非模态+删除关闭"), [this] { // 无 parent 的堆对象:靠 WA_DeleteOnClose 在关闭时自动 delete,避免泄漏 auto *d = new QDialog; d->setWindowTitle(QStringLiteral("WA_DeleteOnClose")); d->setAttribute(Qt::WA_DeleteOnClose); d->show(); setStatus(QStringLiteral("show() + WA_DeleteOnClose:关闭即销毁")); }); // ② QMessageBox(6.4) ------------------------------------------------- auto *g2 = new QGroupBox(QStringLiteral("② QMessageBox(6.4)")); auto *l2 = new QGridLayout(g2); addBtn(l2, 0, 0, QStringLiteral("about"), [this] { QMessageBox::about(this, QStringLiteral("about"), QStringLiteral("这是 about 对话框(只有一个 OK)。")); }); addBtn(l2, 0, 1, QStringLiteral("aboutQt"), [this] { QMessageBox::aboutQt(this, QStringLiteral("aboutQt")); }); addBtn(l2, 0, 2, QStringLiteral("critical"), [this] { QMessageBox::critical(this, QStringLiteral("critical"), QStringLiteral("严重错误!")); }); addBtn(l2, 1, 0, QStringLiteral("information"), [this] { QMessageBox::information(this, QStringLiteral("information"), QStringLiteral("提示信息。")); }); addBtn(l2, 1, 1, QStringLiteral("question"), [this] { const auto r = QMessageBox::question(this, QStringLiteral("question"), QStringLiteral("你确定吗?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); setStatus(QStringLiteral("question 返回:%1") .arg(r == QMessageBox::Yes ? QStringLiteral("Yes") : QStringLiteral("No"))); }); addBtn(l2, 1, 2, QStringLiteral("warning"), [this] { QMessageBox::warning(this, QStringLiteral("warning"), QStringLiteral("警告!")); }); addBtn(l2, 2, 0, QStringLiteral("自定义消息框"), [this] { QMessageBox box(QMessageBox::Question, QStringLiteral("自定义消息框"), QStringLiteral("文档已被修改。"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, this); box.setInformativeText(QStringLiteral("是否保存修改?")); box.setDetailedText(QStringLiteral("这里是详细差异信息……")); box.setDefaultButton(QMessageBox::Save); const int r = box.exec(); const QString name = (r == QMessageBox::Save) ? QStringLiteral("保存") : (r == QMessageBox::Discard) ? QStringLiteral("丢弃") : QStringLiteral("取消"); setStatus(QStringLiteral("自定义消息框返回:%1").arg(name)); }); // ③ 标准对话框(6.2 / 6.5) ------------------------------------------- auto *g3 = new QGroupBox(QStringLiteral("③ 标准对话框(6.2 / 6.5)")); auto *l3 = new QGridLayout(g3); addBtn(l3, 0, 0, QStringLiteral("打开文件"), [this] { const QString f = QFileDialog::getOpenFileName(this, QStringLiteral("打开文件")); if (!f.isEmpty()) setStatus(QStringLiteral("打开文件:%1").arg(f)); }); addBtn(l3, 0, 1, QStringLiteral("保存文件"), [this] { const QString f = QFileDialog::getSaveFileName(this, QStringLiteral("保存文件")); if (!f.isEmpty()) setStatus(QStringLiteral("保存文件:%1").arg(f)); }); addBtn(l3, 1, 0, QStringLiteral("选颜色"), [this] { const QColor c = QColorDialog::getColor(Qt::white, this, QStringLiteral("选颜色")); if (c.isValid()) setStatus(QStringLiteral("选中颜色 RGB(%1,%2,%3)") .arg(c.red()).arg(c.green()).arg(c.blue())); }); addBtn(l3, 1, 1, QStringLiteral("选字体"), [this] { bool ok = false; const QFont f = QFontDialog::getFont(&ok, font(), this, QStringLiteral("选字体")); if (ok) setStatus(QStringLiteral("选中字体:%1").arg(f.family())); }); addBtn(l3, 2, 0, QStringLiteral("输入文字"), [this] { bool ok = false; const QString s = QInputDialog::getText(this, QStringLiteral("输入文字"), QStringLiteral("请输入:"), QLineEdit::Normal, QString(), &ok); if (ok) setStatus(QStringLiteral("输入:%1").arg(s)); }); addBtn(l3, 2, 0, QStringLiteral("输入文字"), [this] { bool ok = false; const QString s = QInputDialog::getText(this, QStringLiteral("输入文字"), QStringLiteral("请输入:"), QLineEdit::Normal, QString(), &ok); if (ok) setStatus(QStringLiteral("输入:%1").arg(s)); }); addBtn(l3, 2, 1, QStringLiteral("自定义对话框"), [] { QDialog *customDialog = new Dialog(); customDialog->setAttribute(Qt::WA_DeleteOnClose); customDialog->exec(); }); root->addWidget(g1); root->addWidget(g2); root->addWidget(g3); root->addWidget(statusLabel); setWindowTitle(QStringLiteral("QDialog 教学综合示例")); resize(520, 430); } private: QLabel *statusLabel = nullptr; // 在 QGridLayout(row, col) 放一个按钮,clicked 连到 lambda template void addBtn(QGridLayout *layout, int row, int col, const QString &text, F &&slot) { auto *btn = new QPushButton(text, this); layout->addWidget(btn, row, col); connect(btn, &QPushButton::clicked, this, std::forward(slot)); } void setStatus(const QString &s) { statusLabel->setText(s); } }; int main(int argc, char *argv[]) { QApplication app(argc, argv); DialogShowcase w; w.show(); // 仅在离屏自动化验证时 200ms 后自动退出(仿 p03 风格); // 正常运行窗口保持,不自动退出。不点按钮则不触发任何对话框。 if (qgetenv("QT_QPA_PLATFORM") == "offscreen") { QTimer::singleShot(200, &app, &QApplication::quit); } return app.exec(); }