当前位置: 首页 > ds >正文

Qt5 高级功能

个人博客:blogs.wurp.top

1. 模型/视图架构 (Model/View Architecture)

这是 Qt 中处理数据与显示分离的核心框架,是理解高级 Qt 开发的关键。

核心概念

  • 模型 (Model): 继承自 QAbstractItemModel 的类。负责管理数据(如一个列表、一个数据库表),并提供统一的接口供视图和委托访问数据。它不关心数据如何显示。
  • 视图 (View): 继承自 QAbstractItemView 的类(如 QListView, QTableView, QTreeView)。负责将模型中的数据展示给用户,并处理用户的操作(如点击、滚动)。
  • 委托 (Delegate): 继承自 QAbstractItemDelegate 的类。负责渲染视图中的每个项(item),并在编辑时为项提供编辑器(如一个输入框、一个下拉菜单)。

为什么使用 M/V?

  • 分离关注点: 数据管理和用户界面分离,代码更清晰、更易维护。
  • 一个模型,多个视图: 你可以让一个 QTableView 和一个 QListView 同时显示同一个模型的数据。在一个视图中修改数据,另一个视图会自动更新。
  • 自定义显示和编辑: 通过自定义委托,你可以完全控制每个单元格的显示和编辑方式(例如,为进度条数据绘制一个实际的进度条控件)。

示例:自定义一个简单的 Table 模型

#include <QApplication>
#include <QTableView>
#include <QStandardItemModel>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 1. 创建模型并设置数据 (这里使用便捷的 QStandardItemModel)QStandardItemModel model(4, 2); // 4行2列for (int row = 0; row < 4; ++row) {for (int col = 0; col < 2; ++col) {QStandardItem *item = new QStandardItem(QString("Row %1, Col %2").arg(row).arg(col));model.setItem(row, col, item);}}// 2. 创建视图并设置模型QTableView tableView;tableView.setModel(&model);tableView.show();return app.exec();
}

更高级的用法: 你可以继承 QAbstractTableModel,重写 rowCount(), columnCount(), data(), 和 setData() 等函数,来封装你自己的数据结构(如一个自定义的容器或一个数据库连接)。


2. 图形视图框架 (Graphics View Framework)

这是一个用于管理和交互大量自定义 2D 图形项的系统。它非常适合开发绘图软件、图表、数据可视化、游戏地图编辑器等。

核心类

  • QGraphicsScene: 场景。它是一个容器,管理所有的图形项(QGraphicsItem)。负责处理事件传播、项之间的碰撞检测等。
  • QGraphicsItem: 图形项。这是你要在屏幕上显示的对象的基类(如椭圆、矩形、自定义图形)。Qt 提供了许多内置项(QGraphicsEllipseItem, QGraphicsTextItem 等),你也可以通过重写 paint()boundingRect() 来自定义项。
  • QGraphicsView: 视图窗口部件。用于将场景的内容可视化并提供观察视口。你可以有多个 View 来观察同一个 Scene,支持缩放和旋转。

高级特性

  • 坐标系系统: 项有场景坐标、自身坐标和父项坐标。支持复杂的变换(QTransform)。
  • 碰撞检测QGraphicsScene 提供了函数来检测项之间的碰撞。
  • 动画: 可以与 QPropertyAnimationQAnimationGroup 结合,轻松为图形项添加动画效果。
  • OpenGL 加速QGraphicsView 可以使用 setViewport(new QOpenGLWidget) 来启用 OpenGL 渲染后端,极大提升大量图形项的渲染性能。

简单示例

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 创建场景QGraphicsScene scene;scene.setSceneRect(0, 0, 400, 300); // 设置场景范围// 创建一个矩形图形项并添加到场景QGraphicsRectItem *rect = new QGraphicsRectItem(0, 0, 100, 50);rect->setPos(50, 50);rect->setBrush(Qt::blue);scene.addItem(rect);// 创建一个视图来显示场景QGraphicsView view(&scene);view.show();return app.exec();
}

3. 多线程与并发 (Multithreading & Concurrent)

Qt 提供了多种方式来处理多线程,从低级到高级,满足不同需求。

1. QThread (低级 API)

传统方式是继承 QThread 并重写 run() 方法。但官方现在更推荐使用以下方法

2. 移动对象到线程 (推荐)

这是 Qt 中最常用和优雅的多线程方法。原理是:

  • 创建一个工作类(Worker),它包含你的耗时操作。这个类继承自 QObject
  • 创建一个 QThread 对象。
  • Worker 对象 moveToThread 到这个新线程中。
  • 通过 信号和槽 来触发工作对象中的函数。这些槽函数将在新线程中执行。
class Worker : public QObject {Q_OBJECT
public slots:void doWork(const QString ¶meter) {// ... 这里是耗时的操作 ...emit resultReady(result);}
signals:void resultReady(const QString &result);
};// 在主线程中
QThread *thread = new QThread;
Worker *worker = new Worker;
worker->moveToThread(thread);// 连接信号和槽
connect(ui->startButton, &QPushButton::clicked, [=](){// 这个 Lambda 在主线程,它发射信号到 worker 所在的线程emit startWork("Task Data"); 
});
connect(worker, &Worker::resultReady, this, &MainWindow::handleResults);
connect(thread, &QThread::finished, worker, &QObject::deleteLater); // 线程结束时清理 workerthread->start();

3. Qt Concurrent (高级 API)

这是一个更高级的框架,用于并行处理算法,类似于 C++ 的 <future><thread>

  • QtConcurrent::run(): 在一个单独的线程中运行一个函数。
  • QtConcurrent::map(), filter(), filteredReduced(): 用于并行处理容器中的元素。
// 在一个线程中运行一个普通函数
QFuture<void> future = QtConcurrent::run([](){// 在另一个线程中执行的代码
});// 并行处理一个 QList
QList<int> list = {1, 2, 3, 4, 5};
QFuture<void> future = QtConcurrent::map(list, [](int &value) {value *= 2; // 将列表中的每个元素乘以2
});
future.waitForFinished(); // 等待操作完成
// 现在 list 是 {2, 4, 6, 8, 10}

4. 网络编程 (Networking)

Qt Network 模块提供了丰富的网络功能。

  • HTTP/HTTPS: 使用 QNetworkAccessManagerQNetworkRequestQNetworkReply 可以轻松实现 HTTP 通信。它是异步的,基于信号和槽。

    QNetworkAccessManager *manager = new QNetworkAccessManager(this);
    QNetworkRequest request(QUrl("https://www.example.com/api/data"));
    QNetworkReply *reply = manager->get(request);connect(reply, &QNetworkReply::finished, [=]() {if (reply->error() == QNetworkReply::NoError) {QByteArray data = reply->readAll();// 处理数据}reply->deleteLater();
    });
    
  • TCP/UDP

    • TCP: 使用 QTcpSocketQTcpServer 实现可靠的流式通信(如自定义协议)。
    • UDP: 使用 QUdpSocket 实现无连接的数据报通信(如广播、视频流)。
  • WebSocketsQWebSocket 提供了对 WebSocket 协议(RFC 6455)的完整支持,非常适合需要全双工、实时通信的应用。


5. QML 与 C++ 混合编程

Qt Quick (QML) 是用于构建现代、动感用户界面的声明式语言。将 QML 的前端优势与 C++ 的后端性能和控制力结合是 Qt 开发的高级模式。

核心交互方式

  1. 将 C++ 对象暴露给 QML

    // MyClass.h - 使用 Q_PROPERTY, Q_INVOKABLE 等导出
    class MyClass : public QObject {Q_OBJECTQ_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    public:Q_INVOKABLE void doSomething();// ...
    };// main.cpp
    MyClass myObj;
    QQuickView view;
    view.engine()->rootContext()->setContextProperty("myObject", &myObj);
    view.setSource(QUrl("qrc:/main.qml"));
    view.show();// 在 QML 中直接使用
    // Text { text: myObject.name }
    // Button { onClicked: myObject.doSomething() }
    
  2. 在 C++ 中创建和管理 QML 组件: 使用 QQmlComponentQQuickView 来加载和实例化 QML 文件,并与之交互。

  3. 在 QML 中调用 C++ 函数: 使用 Q_INVOKABLE 标记的函数可以直接在 QML 中调用。


6. 其它重要高级主题

  • 自定义控件 (Custom Widgets): 通过重写 paintEvent(), mousePressEvent() 等事件,你可以完全自定义一个独一无二的控件。
  • 事件系统 (Event System): 理解事件过滤 (installEventFilter) 和事件处理 (event()) 是进行高级界面交互和自定义控件开发的基础。
  • 样式表 (Qt Style Sheets - QSS): 使用类似 CSS 的语法来美化应用程序的界面,这是实现应用程序换肤功能的基石。
  • 国际化 (Internationalization - i18n): 使用 tr() 宏标记需要翻译的字符串,配合 Qt Linguist 工具,可以轻松实现多语言支持。
  • 插件系统 (Plugin System): 允许你通过插件来扩展应用程序的功能。Qt 自身就是通过插件来支持不同的数据库、图像格式等。

总结

功能模块核心思想典型应用场景
模型/视图数据与显示分离,解耦表格、列表、树形数据展示
图形视图管理大量2D图形项绘图软件、CAD、数据可视化、游戏编辑器
多线程移动对象到线程,信号槽通信后台耗时任务(计算、IO),保持UI响应
网络QNetworkAccessManager 异步请求HTTP API 调用、文件下载、TCP/UDP 通信
QML/C++声明式UI + 高性能逻辑现代移动端/嵌入式UI、动态交互界面
http://www.xdnf.cn/news/18781.html

相关文章:

  • 关于说明锂电池充电芯片实际应用
  • 曲面方程的三维可视化:从数学解析到Python实现
  • 从罗永浩访谈李想中学习现代家庭教育智慧
  • 定时器互补PWM输出和死区
  • 54.Redis持久化-AOF
  • JEI(Journal of Electronic lmaging)SCI四区期刊
  • 控制建模matlab练习16:线性状态反馈控制器-⑤轨迹追踪
  • Linux内核进程管理子系统有什么第三十三回 —— 进程主结构详解(29)
  • 【KO】前端面试四
  • Java八股文-java基础面试题
  • 9.Shell脚本修炼手册---数值计算实践
  • 使用tensorRT10部署yolov5目标检测模型(2)
  • UE5.3 中键盘按键和操作绑定
  • 青少年机器人技术(六级)等级考试试卷-实操题(2021年12月)
  • 深入理解3x3矩阵
  • 11.Shell脚本修炼手册---IF 条件语句的知识与实践
  • 【数据结构】布隆过滤器的概率模型详解及其 C 代码实现
  • mysql没有mvcc之前遇到了什么问题
  • 2025年AI Agent规模化落地:企业级市场年增超60%,重构商业作业流程新路径
  • Hive中的join优化
  • 基于SpringBoot的招聘系统源码
  • 解决Conda访问官方仓库失败:切换国内镜像源的详细教程
  • STAR-CCM+|K-epsilon湍流模型溯源
  • GEO优化供应商:AI搜索时代的“答案”构建与移山科技的引领,2025高性价比实战指南
  • 基于大模型的对话式推荐系统技术架构设计
  • Linux服务环境搭建指南
  • AI绘画落地难?我用Firefly+Marmoset,将2D概念图“反向工程”为3D游戏资产
  • Deep Unfolding Net(LR到HR)
  • Linux 进程间通信之System V 共享内存
  • react中多个页面,数据相互依赖reducer解决方案