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

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.dtcms.com/a/346771.html

相关文章:

  • 当 AI 学会 “理解” 人类:自然语言处理的进化与伦理边界
  • 商品与股指类ETF期权买卖五档Tick分钟级历史行情数据分析
  • 【KO】前端面试三
  • GPT-5:天变了吗?还是风停了?
  • 基于Python的农作物病虫害防治网站 Python+Django+Vue.js
  • MySQL奔溃,InnoDB文件损坏修复记录
  • [2025CVPR-目标检测方向]PointSR:用于无人机视图物体检测的自正则化点监控
  • 尤弥尔传奇能够进行挂机搬砖吗?
  • AI实现超级客户端打印 支持APP 网页 小程序 调用本地客户端打印
  • 爬小红书图片软件:根据搜索关键词,采集笔记图片、正文、评论等
  • Angular初学者入门第三课——工厂函数(精品)
  • 游戏广告投放数据分析项目:拆解投放的“流量密码”
  • kail的浏览器连接不上网
  • 20250823给荣品RD-RK3588开发板刷Rockchip原厂的Buildroot【linux-5.10】时调通AP6275P的WIFI【源码部分】
  • 从 M4S 到 MP4:用 FFmpeg 轻松合并音视频文件
  • 达梦数据库统计信息收集
  • 无人机光伏巡检误检率↓79%!陌讯多模态融合算法在组件缺陷检测的落地优化
  • 【85页PPT】数字化转型LIMS大型企业智能制造之LIMS实验室管理系统产品解决方案(附下载方式)
  • webrtc弱网-SendSideBandwidthEstimation类源码分析与算法原理
  • 使用dism++备份系统时,出现“句柄无效”错误的解决方法
  • 重构实训生态:旅游管理虚拟仿真实训室的标准落地与价值创新
  • 某电器5G智慧工厂网络建设全解析
  • 【ABAP4】创建Package
  • 数字经济、全球化与5G催生域名新价值的逻辑与实践路径
  • Autosar CAN开发06(CAN通讯开发需求-CAN矩阵)
  • 突破传统文本切片的瓶颈:AntSK-FileChunk语义切片技术详解前言:为什么我们需要重新思考文本切片?
  • RHCSA--命令(二)
  • 一种通过模板输出Docx的方法
  • Agent Lightning:让任何AI智能体通过强化学习实现高效训练
  • 简单介绍计算机的工作过程