第 10 章 对话框、剪贴板与拖放
10.1 标准对话框
Qt 提供一批开箱即用的对话框:
QString path = QFileDialog::getOpenFileName(this, "选择文件", QDir::homePath(),
"文本 (*.txt);;所有 (*)");
QColor c = QColorDialog::getColor(Qt::white, this);
QFont f = QFontDialog::getFont(nullptr, this);
QString txt = QInputDialog::getText(this, "重命名", "新名称:");
QMessageBox::warning(this, "提示", "文件已修改,是否保存?");
10.2 自定义对话框
继承 QDialog,通过 accept() / reject() 关闭。同步展示:
MyDialog dlg(this);
if (dlg.exec() == QDialog::Accepted) {
useSettings(dlg.result());
}
模态阻塞事件循环之外的窗口(可选 Qt::WindowModal 只阻塞父窗口)。异步展示用 open() + 连接 accepted() / rejected() 信号。
10.3 剪贴板
QGuiApplication::clipboard()->setText("copied");
QString s = QGuiApplication::clipboard()->text();
要粘图或自定义 MIME 数据,用 QMimeData:clipboard()->setMimeData(new QMimeData)。
10.4 拖放
拖出:
void MyList::mouseMoveEvent(QMouseEvent *e)
{
if (!(e->buttons() & Qt::LeftButton)) return;
auto *drag = new QDrag(this);
auto *mime = new QMimeData;
mime->setText(currentItem()->text());
drag->setMimeData(mime);
drag->exec(Qt::CopyAction | Qt::MoveAction);
}
接收:重写 dragEnterEvent 决定是否接受,dropEvent 处理数据。别忘了 setAcceptDrops(true)。
第 11 章 资源、样式与国际化
11.1 Qt 资源系统(.qrc)
把图标、翻译、QSS 等打进可执行文件,发布时不用担心相对路径:
<!-- resources.qrc -->
<RCC>
<qresource prefix="/">
<file>icons/open.svg</file>
<file>styles/dark.qss</file>
</qresource>
</RCC>
代码里用 ":/icons/open.svg" 引用。CMake 打开 AUTORCC 后,只要把 .qrc 加到 add_executable 里即可。
11.2 Qt Style Sheets(QSS)
类 CSS 语法,用 QApplication::setStyleSheet() 或对单个 widget 应用:
QPushButton {
background: #3D7EFF;
color: white;
border-radius: 6px;
padding: 6px 14px;
}
QPushButton:hover { background: #5B92FF; }
QPushButton:pressed{ background: #2A5FCF; }
QPushButton:disabled { background: #999; }
支持子控件选择器(QComboBox::drop-down)和属性选择器(QPushButton[flat="true"])。QSS 会覆盖平台原生风格,重度使用时关闭原生风格保持一致(QApplication::setStyle("Fusion"))。
11.3 国际化(i18n)
三步走:
- 源码里所有面向用户的字符串用
tr()包起来:tr("打开文件")。 - CMake 用
qt_add_translations或手动跑lupdate生成.ts,linguist编辑翻译,lrelease生成.qm。 - 运行时加载:
QTranslator tr;
if (tr.load(QLocale(), "myapp", "_", ":/i18n"))
app.installTranslator(&tr);
翻译加载必须在创建 UI 之前,否则已经生成的字符串不会自动重译(除非重写 changeEvent() 处理 QEvent::LanguageChange)。
11.4 QSettings
跨平台持久化用户偏好:
QSettings s("MyCorp", "MyApp");
s.setValue("mainwindow/geometry", saveGeometry());
s.setValue("mainwindow/state", saveState());
restoreGeometry(s.value("mainwindow/geometry").toByteArray());
restoreState(s.value("mainwindow/state").toByteArray());
Windows 默认写注册表,macOS 写 plist,Linux 写 ini。想统一用 ini,可以在 main() 里 QSettings::setDefaultFormat(QSettings::IniFormat)。
第 12 章 打包与部署
代码写完只是第一步,还得让别人的机器能跑起来。
12.1 Release 构建
- Qt Creator 顶部构建套件旁切换到 Release(或
cmake --build build --config Release)。 - Release 会关闭调试信息、开优化,体积和性能差异很大。
- 想在 Release 保留符号方便追踪 crash,加
-DCMAKE_BUILD_TYPE=RelWithDebInfo。
12.2 Windows:windeployqt
windeployqt --release --dir dist path\to\MyApp.exe
windeployqt 会把需要的 Qt DLL、平台插件(platforms/qwindows.dll)、样式、翻译一并拷到目标目录。MSVC 构建的还要带上 VC++ 运行时(vcredist)。
12.3 macOS:macdeployqt
macdeployqt MyApp.app -dmg
生成一个自包含的 .app 或直接打包成 .dmg。上架需要签名和公证(codesign + notarytool)。
12.4 Linux
Linux 生态碎片化,常见做法:
- AppImage:单文件可执行,配合
linuxdeployqt或linuxdeploy+linuxdeploy-plugin-qt。 - Flatpak / Snap:发行版无关的沙箱包。
- 传统 deb/rpm:交给发行版打包。
12.5 静态 vs 动态链接
- 动态(LGPL 友好、默认):体积小,用户端要一起分发 Qt DLL。
- 静态(需自己重编 Qt):单个 exe,但商用需要商业许可(LGPL 静态链接要额外满足重链接义务)。
12.6 版本与图标
- Windows 上通过
.rc文件加图标和版本信息,CMake 里add_executable(app WIN32 main.cpp app.rc)。 - macOS 通过
Info.plist(CMakeMACOSX_BUNDLE+MACOSX_BUNDLE_INFO_PLIST)。
附录 A 调试与常见陷阱
A.1 调试小工具
qDebug() << x:控制台打印,支持大多数 Qt 类型。Q_ASSERT(cond):调试期断言。qFatal("..."):直接终止程序并留栈。QLoggingCategory:分类日志,可通过环境变量QT_LOGGING_RULES="myapp.*=true"动态开关。- GammaRay:Qt 官方(KDAB 维护)的运行时探查器,可以看对象树、信号槽连接、模型内容,排 UI 问题极好用。
A.2 高频踩坑清单
- 忘写
Q_OBJECT→ 信号槽不工作、qobject_cast返回空。 - 忘调
moc/AUTOMOC→ 链接错误undefined reference to vtable。 - 栈上 QWidget 又设了父对象 → 程序退出时崩溃(重复 delete)。
- 跨线程直接操作 UI → 概率性崩溃,现象很随机。
- 在
paintEvent外构造QPainter(widget)→ 警告 + 什么也画不出。 QStringLiteral("...")vs 普通"...":热路径用前者避免运行时构造。emit关键字:纯装饰,写不写都能编译,但建议写,让读者一眼看出是信号。- 忘
setLayout/ 顶层没加 layout → 缩放后控件挤在角落。 - 在信号槽里
delete sender()→ 用deleteLater(),让事件循环处理完当前事件再释放。

175

被折叠的 条评论
为什么被折叠?



