C++ Qt5 范例开发大全
作者:Longki|186 页|以 Windows + Qt 5.1.1 (MinGW) 为环境,14 章共 80+ 个可运行范例,覆盖 Qt 桌面开发常用模块。
一、书籍定位与特点
- 面向 Qt 初学者的”菜谱式”教程:每个范例按”需求 → 参照工程 → .h 声明 → .cpp 实现”组织,代码可直接拷贝运行。
- 技术栈:Qt 5.1.1 + MinGW 4.8 + Qt Creator,全部基于 C++ Widgets(非 QML/Qt Quick)。
- 知识覆盖:窗体、控件、文件、图形、多媒体、系统 API、注册表、数据库、网络(TCP/UDP/SMTP)、进程线程、加密、打包部署,形成完整的 Windows 桌面应用开发链路。
- 局限:部分方案已过时(QAxWidget 播 Flash、Windows 注册表、wininet.dll),但核心 Widgets/Network/Sql/Concurrent API 在 Qt5/Qt6 中仍适用。
二、Qt 框架核心概念
2.1 三大窗口基类
| 基类 | 用途 | 典型场景 |
|---|---|---|
QMainWindow | 带菜单栏、工具栏、状态栏的主窗口 | 应用主框架,中央放编辑区/画布 |
QWidget | 所有 UI 对象的基类 | 自定义窗口、登录框等简单界面 |
QDialog | 对话框基类,模态/非模态 | 短期任务、文件选择、参数配置 |
2.2 信号与槽(Signals/Slots)
Qt 用类型安全的 signal/slot 替代回调函数,是组件通信的核心机制:
connect(button, SIGNAL(clicked()), this, SLOT(onClick()));
// Qt5 新语法(编译期检查):
connect(button, &QPushButton::clicked, this, &MainWindow::onClick);2.3 元对象系统(moc)
- Qt 的
Q_OBJECT宏触发 moc(Meta Object Compiler)生成信号槽元代码。 - 自定义类用信号槽必须继承
QObject并在类声明中加Q_OBJECT。 - pro 文件中
QT +=控制模块:sql(数据库)、network(网络)、qaxcontainer(ActiveX)。
三、窗体与界面(第 2、4 章)
3.1 窗体控制常用 API
setWindowTitle("标题");
setMaximumSize(300,300); setMinimumSize(300,300); // 固定大小
move(100,100); // 位置
setStyleSheet("background:red"); // QSS 样式
setWindowIcon(QIcon(":/ico")); // 图标(资源文件)
setWindowFlags(Qt::FramelessWindowHint); // 无边框
setWindowFlags(Qt::WindowCloseButtonHint); // 只留关闭按钮
setAttribute(Qt::WA_TranslucentBackground, true); // 背景透明3.2 无边框窗体拖动
重写三个鼠标事件,用全局坐标差移动窗口:
void mousePressEvent(QMouseEvent *e) { last = e->globalPos(); }
void mouseMoveEvent(QMouseEvent *e) { move(x()+e->globalX()-last.x(),
y()+e->globalY()-last.y()); }
void mouseReleaseEvent(QMouseEvent *e) { /* 同 move 逻辑 */ }3.3 标准对话框
QFileDialog::getOpenFileName()— 文件选择,可用过滤器"Text(*.txt);;All(*.*)"QColorDialog::getColor()— 颜色选择,配合QPalette改控件颜色QMessageBox::warning/information()— 消息提示QCalendarWidget— 日历,点击信号clicked(QDate)
3.4 定时器刷新
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &MainWindow::onTick);
timer->start(1000); // 周期 1 秒
QTimer::singleShot(3000, obj, SLOT(close())); // 单次延时四、常用控件全景(第 3 章)
4.1 输入控件
| 控件 | 要点 |
|---|---|
QPushButton | clicked/released 信号;setEnabled(false) 禁用 |
QLabel | 支持 QSS:font-size/color/font-weight/font-style |
QLineEdit | setMaxLength()、setEchoMode(Password) 密码框 |
QTextEdit | 富文本/HTML(<br/> 换行),setText() |
QPlainTextEdit | 纯文本多行,setPlainText() |
QComboBox | addItems(QStringList),currentText() |
QFontComboBox | 字体选择下拉框,系统字体枚举 |
QSpinBox | setRange(0,200)、setValue()、setPrefix/setSuffix |
QTimeEdit/QDateEdit | 配合 QDateTime::currentDateTime() 初始化 |
4.2 选择控件
QRadioButton:互斥单选,setChecked(true)默认项,用sender()判断信号来源。QCheckBox:多选,checkState() == Qt::Checked判断,取消选中时用QString::replace()移除文本。QScrollBar:与 SpinBox 双向绑定 — 两者valueChanged(int)互连可实现联动。
4.3 Model/View 控件(重点)
Qt 的模型/视图架构是数据展示的核心:
// 列表:QStringListModel
QStringList data{"数学","语文"};
listView->setModel(new QStringListModel(data));
// 树:QStandardItemModel + appendRow 建层级
auto *model = new QStandardItemModel(3, 2); // 3行2列
model->setHorizontalHeaderItem(0, new QStandardItem("列名"));
auto *parent = new QStandardItem("外语");
parent->appendRow(new QStandardItem("外语A")); // 子节点
// 表格:setItem(row, col, item)
model->setItem(0, 0, new QStandardItem("数据"));
tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); // 只读4.4 布局管理
QHBoxLayout/QVBoxLayout:横/纵排列,addWidget()、setSpacing()。QGridLayout:网格,addWidget(w, row, col, rowSpan, colSpan)。QGroupBox:带标题的分组容器,内部嵌套其他布局。QTabWidget:多标签页,addTab(new TabWidget, "名称"),每个 tab 是独立 QWidget 子类。
4.5 菜单、工具栏与托盘
// QAction = 命令对象,可同时挂在菜单和工具栏
auto *act = new QAction(QIcon(":/new"), tr("新建"), this);
act->setShortcut(QKeySequence("Ctrl+N"));
act->setStatusTip("状态栏提示");
connect(act, &QAction::triggered, this, &MainWindow::newFile);
menuBar()->addMenu(tr("文件"))->addAction(act);
addToolBar(tr("工具"))->addAction(act);
// 系统托盘
auto *tray = new QSystemTrayIcon(QIcon(":/ico"), this);
tray->setToolTip("提示");
tray->setContextMenu(trayMenu);
tray->show();
tray->showMessage("标题","内容", QSystemTrayIcon::Information, 10000);最小化到托盘:重写 changeEvent,检测 WindowStateChange + isMinimized() 后调 hide()。
五、文件与配置(第 5 章)
5.1 文件/目录操作
QDir().mkdir(path); // 创建文件夹,exists() 先判重
QFile file(path);
file.open(QIODevice::ReadWrite | QIODevice::Text);
file.write(content.toUtf8()); // 中文必须 toUtf8()
QFile::remove(path); // 删除
QFile::rename(old, new); // 重命名(用 QFileInfo 取目录)文件编辑典型模式:QFileDialog 取路径 → QTextStream 流式读写 → atEnd() 循环。
5.2 INI 配置文件(QSettings)
auto *ini = new QSettings("config.ini", QSettings::IniFormat);
ini->setValue("node/key", "value"); // 写:分组/键
QString v = ini->value("node/key").toString(); // 读QSettings::NativeFormat 在 Windows 上即操作注册表(HKEY_CURRENT_USER\\Software\\...),同一套 API 兼顾 INI 和注册表。
5.3 XML 流式读写
- 写:
QXmlStreamWriter,writeStartDocument/Element、writeAttribute、writeTextElement,setAutoFormatting(true)美化。 - 读:
QXmlStreamReader,readNext()推进,isStartElement()+name()判断节点,readElementText()取值。
六、图形图像与特效(第 6 章)
6.1 两种绘图体系
-
Graphics View 框架(场景/视图/图元):
QGraphicsScene管理图元,addLine/addEllipse/addSimpleText。QGraphicsView视口显示场景,setCentralWidget(view)。QPen控制线条:setStyle(Qt::DashDotLine)、setWidth、setCapStyle。
-
QPainter 低级绘制(重写
paintEvent):void paintEvent(QPaintEvent*) { QPainter p(this); p.drawPixmap(20,20,200,257, QPixmap(":/dog")); p.drawText(rect, Qt::AlignCenter, "文字"); }
6.2 QImage 图像处理
QImage img; img.load(":/hd");
img.mirrored(true, false); // 水平翻转
img.scaled(100,100, Qt::IgnoreAspectRatio); // 缩放
QMatrix m; m.rotate(88);
img.transformed(m); // 旋转
QPainter painter(&img); painter.shear(0.5,0); // 扭曲
image.save("out.jpg","JPG",100); // quality 0-1006.3 图形特效(QGraphicsEffect 体系)
auto *blur = new QGraphicsBlurEffect; blur->setBlurRadius(5);
auto *colorize = new QGraphicsColorizeEffect; colorize->setColor(QColor(0,0,192));
auto *shadow = new QGraphicsDropShadowEffect; shadow->setOffset(8,8);
auto *opacity = new QGraphicsOpacityEffect; opacity->setOpacity(0.5);
label->setGraphicsEffect(effect); // 一个控件同时只能挂一个 effectGIF 动画:QMovie + QLabel::setMovie() + movie->start()。
七、多媒体(第 7 章)
- Qt 5.1 时代播放方案依赖 Windows ActiveX:
QAxWidget调用 WMP({22D6F312-...})或 Flash({d27cdb6e-...}),pro 加CONFIG += qaxcontainer。 - 现代 Qt 应改用
QMediaPlayer + QVideoWidget(Qt Multimedia),书中的播放状态机(Stopped/Paused/Playing)、进度条blockSignals防递归、timerEvent轮询位置等思路仍可借鉴。 - 逐帧图片动画:
QTimer周期切换QPixmap::load路径实现。
八、系统交互(第 8、9 章)
8.1 系统信息
QApplication::desktop()->screenGeometry(); // 屏幕分辨率
QHostInfo::localHostName(); // 主机名
QHostInfo::fromName(name).addresses(); // 本机 IP(过滤 IPv4)
QHostInfo::lookupHost(url, this, SLOT(lookedUp(QHostInfo))); // 异步 DNS
QProcess::systemEnvironment(); // 全部环境变量8.2 执行外部命令
auto *proc = new QProcess(this);
connect(proc, &QProcess::readyRead, this, &MainWindow::readOut);
proc->start("ipconfig"); // 也支持 start(cmd, QStringList args)
// readAll() 在槽中累积输出;注意路径/中文参数用参数列表更安全8.3 键盘事件
重写 keyPressEvent(QKeyEvent*),用 event->key() == Qt::Key_Q 判断。
8.4 注册表(Windows)
QSettings 以 NativeFormat 直接读写 HKEY_CURRENT_USER\Software\...,书中示范修改 IE 主页(Main/Start Page)——仅作技术说明,实际开发应避免此类操作。
九、数据库(第 10 章)
9.1 驱动与连接
QT += sqlqDebug() << QSqlDatabase::drivers(); // 列出可用驱动 QSQLITE/QODBC...
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("db.db");
db.open();Access 通过 ODBC 连接串:DRIVER={Microsoft Access Driver (*.mdb)};DBQ=path;UID=;PWD=。
9.2 增删查与模型展示
// 参数化插入(防注入)
QSqlQuery q;
q.prepare("insert into person(name) values(:n)");
q.bindValue(":n","张三");
q.exec();
// 表模型直接绑表格
QSqlTableModel *m = new QSqlTableModel;
m->setTable("person"); m->select();
tableView->setModel(m);SQLite 建表范例:id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(50), time TIMESTAMP default CURRENT_TIMESTAMP。
十、网络编程(第 11 章,含金量最高)
10.1 TCP 聊天(C/S 架构)
服务端三层结构值得借鉴:
TcpServer : QTcpServer:重写incomingConnection(socketDescriptor),每个连接创建一个TcpSocket存入QList,广播时遍历 write。TcpSocket : QTcpSocket:构造时连readyRead → dataReceived,读到数据后 emit 信号交给 server 广播;断线 emitdisconnected(descriptor)供 server 清理列表。- 客户端
QTcpSocket::connectToHost(ip, port),维护在线状态布尔值,退出时发 “Leave Chat Room” 再disconnectFromHost()。
10.2 UDP 局域网广播 + 文件传输
综合范例,架构清晰:
- UDP 端口 45454,
bind(ShareAddress | ReuseAddressHint),消息用QDataStream序列化,枚举MessageType{Message, NewParticipant, ParticipantLeft, FileName, Refuse}。 - 用户上线/下线通过广播消息同步,在线用户表
QTableWidget维护(用户名/主机名/IP)。 - 文件传输走独立 TCP(端口 6666):UDP 先协商文件名和双方 IP,接收方弹窗确认后启动
tcpclient,发送方tcpserver监听;带TotalBytes/fileNameSize包头、进度条、速度与剩余时间估算。 - 细节:
eventFilter实现回车发送;QNetworkInterface::allAddresses()获取本机 IPv4。
10.3 SMTP 发信
QTcpSocket 直连 smtp.qq.com:25,手工走 SMTP 协议:helo → auth login → base64(账号) → base64(密码) → mail from → rcpt to → data → . → quit。现代环境普遍用 465/587 + SSL/TLS(QSslSocket),且需授权码而非账号密码。
10.4 网络状态
QLibrary 动态加载 wininet.dll,解析 InternetGetConnectedState 函数指针判断拨号/局域网/代理。现代跨平台可用 QNetworkConfigurationManager。
十一、进程与线程(第 12 章)
11.1 进程管理器(Windows API)
CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0) 拍进程快照 → Process32First/Next 遍历 PROCESSENTRY32(szExeFile + th32ProcessID)→ 结束进程用 QProcess::start("Taskkill", {"/pid", pid})。
11.2 两种线程用法
QThread:thread->start()启动,静态函数QThread::sleep(1)挂起。书中直接在函数内 new QThread 但未重写 run(),仅演示 API;实际耗时任务应子类化 QThread 重写run()或用 worker-object moveToThread 模式。QRunnable + QThreadPool(轻量任务推荐): 注意:书中在 worker 线程直接更新 UI 控件是错误示范,Qt 要求 GUI 操作只能在主线程(应通过信号回传)。class Job : public QRunnable { void run() override { for(...) progressBar->setValue(i); } }; QThreadPool::globalInstance()->start(new Job); // 自动 delete
十二、数据安全(第 13 章)
QByteArray:toBase64()/fromBase64()、toHex()—— 是编码不是加密。- MD5(Qt 内置):
QCryptographicHash h(QCryptographicHash::Md5); h.addData("pwd"); QString md5 = h.result().toHex(); // 单向,用于比对而非解密 - AES:Qt 无内置,书中用第三方
TAesClass,演示 InitializePrivateKey(16,key) → OnAesEncrypt/Uncrypt 流程。生产环境建议用 QCryptographicHash 支持的 SHA 系列或外部 OpenSSL/libsodium。 - 随机数:
qsrand(QTime::currentTime().msec()+sec*1000)播种,qrand()%1000;现代代码用QRandomGenerator::global()->bounded(1000)。
十三、打包部署(第 14 章)
Windows 发布 Qt 程序的标准流程(书中工具古老,流程不变):
- Release 模式编译出 exe。
- 拷贝 exe 到空目录,用依赖检查工具(书中 hap-depends,现代用
windeployqt或 Dependencies)找出缺失 DLL。 - 从 Qt 的
mingw48_32/bin拷贝运行时 DLL;必须额外拷贝plugins/platforms/qwindows.dll(保持 platforms 子目录结构),否则程序启动即崩。 - 打包:现代直接用官方
windeployqt --release xxx.exe自动收集;安装包用 Inno Setup(脚本化、轻量)或 NSIS。
十四、可复用经验总结
- 资源文件管理:图标/图片统一放入
.qrc,用:/前缀/别名访问,避免部署时丢图。 - 中文编码:文件读写一律
toUtf8();源码中文字符串注意源码编码与QString::fromUtf8。 - UI 与数据解耦:列表/树/表格一律走 Model/View,数据用
QStandardItemModel/QSqlTableModel,不要直接往控件里塞数据。 - 信号槽防循环:进度条双向联动时用
blockSignals(true)包裹程序化设值。 - 网络通信协议设计:自定义协议先发定长包头(总长度、文件名长度),再发载荷;接收方按字节数状态机解析(书中 TCP 文件传输是好范例)。
- 线程铁律:worker 线程不能碰 QWidget;跨线程通信用信号槽(QueuedConnection 自动生效)。
- 跨平台意识:书中注册表/wininet/Taskkill/QAxWidget 均为 Windows-only;Linux/嵌入式(如树莓派)上需替换为跨平台 API。
关联笔记
- Qt5-Cadaques-Qt-Quick-QML编程全指南 — Qt Quick/QML 路线,与本书 Widgets 路线互补
- Qt样式表QSS开发总结-葵花宝典 — 本书第 2/3 章 QSS 的深入扩展
- 实践参照:工作文档中飞凌 i.MX6 Qt 移植(Qt 4.8.5 嵌入式环境)系列笔记
- 网络编程理论:TCP-IP详解卷1-协议-原书第2版、TCP-IP详解 卷2:实现
- 线程理论:C++-Concurrency-in-Action-2nd-Edition