文章目录
qRegisterMetaType
主要用于在 Qt 的元对象系统中注册自定义类型,以便这些类型能够用于信号和槽机制、QVariant 以及跨线程通信等场景。
struct MyData {
int id;
QString name;
};
Q_DECLARE_METATYPE(MyData); // 声明元类型
// 在使用前注册:
qRegisterMetaType<MyData>("MyData");
// 之后可以用于信号槽:
QObject::connect(sender, &Sender::mySignal, receiver, &Receiver::mySlot);
connect()
连接信号和槽,实现对象通信。
用法:connect(发信对象,信号,接受槽对象,槽函数)
connect(sender, &Class::Signal, receiver, &Class::Slot)
QMetaObject::Connection QObject::connect(
const QObject *sender, // 发送信号的对象
const char *signal, // 信号(SIGNAL() 宏或 &Class::Signal)
const QObject *receiver, // 接收槽的对象
const char *method, // 槽函数(SLOT() 宏或 &Class::Slot)
Qt::ConnectionType type = Qt::AutoConnection
);

QAbstractListModel
任何需要频繁更新的列表,用法如下:
1. QAbstractListModel用法结构
QAbstractListModel基本用法(C++ 端实现)
(1)创建自定义模型类
// MyListModel.h
#include <QAbstractListModel>
#include <QStringList>
class MyListModel : public QAbstractListModel {
Q_OBJECT
public:
explicit MyListModel(QObject *parent = nullptr);
// 必须重写的函数
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
// 可选:定义 Role 名称(供 QML 使用)
QHash<int, QByteArray> roleNames() const override;
// 自定义方法:修改数据
Q_INVOKABLE void addItem(const QString &text);
Q_INVOKABLE void removeItem(int index);
private:
QStringList m_data; // 实际数据存储
};
(2)实现模型逻辑
// MyListModel.cpp
MyListModel::MyListModel(QObject *parent) : QAbstractListModel(parent) {
// 初始化数据
m_data << "Apple" << "Banana" << "Orange";
}
// 重载
int MyListModel::rowCount(const QModelIndex &parent) const {
Q_UNUSED(parent);
return m_data.size();
}
// 重载
QVariant MyListModel::data(const QModelIndex &index, int role) const {
if (!index.isValid() || index.row() >= m_data.size())
return QVariant();
// 根据 Role 返回不同数据
if (role == Qt::DisplayRole || role == TitleRole)
return m_data.at(index.row());
return QVariant();
}
// 重载
QHash<int, QByteArray> MyListModel::roleNames() const {
return {
{TitleRole, "title"} // QML 中通过 model.title 访问
};
}
void MyListModel::addItem(const QString &text) {
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_data.append(text);
endInsertRows();
}
void MyListModel::removeItem(int index) {
if (index < 0 || index >= m_data.size()) return;
beginRemoveRows(QModelIndex(), index, index);
m_data.removeAt(index);
endRemoveRows();
}
(3)注册模型到QML
// main.cpp
#include <QQmlApplicationEngine>
#include <QQmlContext>
qmlRegisterType<MyListModel>("CustomModels", 1, 0, "MyListModel");
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
QAbstractListModel在QML 端使用
**(1)基本 ListView 绑定 **
// main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import CustomModels 1.0
ListView {
width: 200; height: 300
model: MyListModel { id: myModel }
delegate: Text {
text: model.title // 对应 roleNames() 中的 "title"
}
}
(2)动态操作模型
Column {
Button {
text: "Add Item"
onClicked: myModel.addItem("New Item " + Math.random())
}
Button {
text: "Remove First"
onClicked: myModel.removeItem(0)
}
}
2. QAbstractListModel的QModelIndex
关键方法
| 方法 | 说明 |
|---|---|
row() | 返回行号(0-based) |
column() | 返回列号(0-based) |
parent() | 返回父索引 |
data(int role) | 获取指定角色的数据 |
sibling() | 获取同级索引 |
isValid() | 检查索引是否有效 |
核心属性
| 属性/方法 | 类型 | 说明 | 示例 |
|---|---|---|---|
| row() | int | 获取索引指向的行号(从0开始) | index.row() → 2 |
| column() | int | 获取索引指向的列号(从0开始) | index.column() → 1 |
| parent() | QModelIndex | 获取父级索引(顶层返回空索引) | index.parent().isValid() → false |
| internalId() | quintptr | 内部标识符(用于自定义模型) | index.internalId() → 12345 |
| internalPointer() | void* | 指向关联数据的指针(高级用法) | static_cast<Item*>(index.internalPointer()) |
| model() | const QAbstractItemModel* | 获取所属模型对象 | index.model()->rowCount() |
QtConcurrent 详解 (异步执行)
QtConcurrent 是 Qt 提供的高级 API,用于简化多线程编程,无需直接管理 QThread。
1. 核心功能
- 并行计算:自动利用多核处理器
- 简化线程管理:无需显式创建线程
- 安全的数据访问:通过 Future/Promise 模式处理结果
- 与 Qt 事件循环集成:支持信号槽通知
2. 主要模块
2.1 并行算法
// 并行映射
QList<int> list = {1, 2, 3, 4};
QFuture<void> future = QtConcurrent::map(list, [](int &x){ x *= 2; });
// 并行过滤
QFuture<QList<int>> filtered = QtConcurrent::filtered(list, [](int x){ return x > 2; });
// 并行归约
int sum = QtConcurrent::blockingReduced(list, std::plus<int>());
2.2 异步算法
// 运行函数并返回 Future
QFuture<QString> future = QtConcurrent::run([](){
return QImage("large.png").scaled(1000, 1000).save("thumbnail.jpg");
});
// 获取结果(阻塞方式)
QString result = future.result();
// 非阻塞方式获取结果
QFutureWatcher<QString> *watcher = new QFutureWatcher<QString>();
connect(watcher, &QFutureWatcher<QString>::finished, [=](){
qDebug() << "Result:" << watcher->result();
});
watcher->setFuture(future);
QFuture 深度解析
1. 核心概念
QFuture<T> 是 Qt 提供的异步计算结果容器,代表未来将会可用的数据。它与 QtConcurrent 和 QPromise 配合使用,实现非阻塞的多线程编程。
2. 关键特性
- 异步结果获取:不阻塞主线程
- 进度跟踪:支持任务进度监控
- 取消支持:可中断正在执行的任务
- 多结果处理:适用于返回多个值的场景(如
mapped())
3. 核心方法
状态检查
| 方法 | 说明 |
|---|---|
isStarted() | 任务是否已开始 |
isFinished() | 任务是否完成 |
isCanceled() | 任务是否被取消 |
isRunning() | 任务是否正在运行 |
结果获取
| 方法 | 说明 |
|---|---|
result() | 阻塞等待并返回结果 |
resultAt(index) | 获取多结果中的指定项 |
results() | 返回所有结果的列表(Qt 6+) |
控制方法
| 方法 | 说明 |
|---|---|
cancel() | 尝试取消任务 |
pause() | 暂停任务(需任务支持) |
resume() | 恢复暂停的任务 |
4. 基本使用流程
创建 Future
// 通过 QtConcurrent 创建
QFuture<int> future = QtConcurrent::run([](){
QThread::sleep(2);
return 42;
});
// 通过 QPromise 创建(Qt 6+)
QPromise<int> promise;
QFuture<int> manualFuture = promise.future();
Qt Q_PROPERTY 详解
1. 核心作用
Q_PROPERTY 是 Qt 元对象系统的核心宏之一,用于声明类的属性,实现以下功能:
- QML 绑定:支持属性与 QML 的双向绑定
- 动态访问:通过
property()和setProperty()方法操作 - 自动通知:属性变更触发信号通知
- 代码生成:由 moc 生成元对象代码
2. 基本语法结构
Q_PROPERTY(type name
READ getFunction
WRITE setFunction
NOTIFY notifySignal
RESET resetFunction
DESIGNABLE bool
SCRIPTABLE bool
STORED bool
USER bool)
因此getFunction setFunction函数已经算是被声明了,需要进一步去定义它。
3. 必须参数详解
| 参数 | 说明 | 示例 |
|---|---|---|
| type | 属性数据类型 | QString, int, bool 等 |
| name | 属性名称 | text, isActive 等 |
| READ | 获取属性值的成员函数 | QString text() const |
4. 可选参数说明
| 参数 | 作用 | 典型用法 |
|---|---|---|
| WRITE | 设置属性值的槽函数 | void setText(const QString&) |
| NOTIFY | 属性变更信号 | void textChanged() |
| RESET | 重置为默认值的函数 | void resetText() |
| DESIGNABLE | Qt Designer 可见性 | DESIGNABLE true |
| STORED | 序列化时是否保存 | STORED true |
QVector 深度解析
1. 基本概念
QVector<T> 是 Qt 提供的动态数组容器类(Qt 6 后改名为 QList<T>),提供高效的随机访问和尾部操作。
类似于python中的list列表。
2. 核心特性
- 动态扩容:自动管理内存
- 值语义:隐式共享(Copy-On-Write)
- STL兼容:提供标准迭代器
- 类型安全:模板类设计
3. 主要操作(时间复杂度)
基本操作
| 操作 | 时间复杂度 | 示例 |
|---|---|---|
| 随机访问 | O(1) | vec[0] |
| 尾部追加 | 平摊 O(1) | vec.append(x) |
| 头部插入 | O(n) | vec.prepend(x) |
| 中间插入 | O(n) | vec.insert(2, x) |
| 查找 | O(n) | vec.contains(x) |
容量管理
| 方法 | 说明 |
|---|---|
resize(n) | 调整元素数量 |
reserve(n) | 预分配内存 |
capacity() | 返回已分配空间 |
squeeze() | 释放多余内存 |
4. 与 std::vector 对比
| 特性 | QVector | std::vector |
|---|---|---|
| 内存策略 | 隐式共享 | 直接拷贝 |
| 接口风格 | Qt风格 | STL风格 |
| 性能 | 侧重快速遍历 | 侧重随机访问 |
| 线程安全 | 只读操作线程安全 | 需要手动同步 |
5. 基本使用示例
创建和初始化
// 空向量
QVector<int> vec1;
// 指定大小初始化
QVector<QString> vec2(10, "default");
// 列表初始化
QVector<double> vec3 = {1.1, 2.2, 3.3};
QHash
哈希表,就是python中的字典
MVC框架
| 组件 | 职责 | 类比 |
|---|---|---|
| Model(模型) | 数据管理和业务逻辑 | 仓库管理员 |
| View(视图) | 数据展示和用户界面 | 商店橱窗 |
| Controller(控制器) | 处理用户输入和协调交互 | 售货员 |

qmlRegister和setContextProperty
Model定义好后,需要注册,Qt qml有两个注册函数:qmlRegisterType 和 qmlRegisterSingletonType
qmlRegister
| 特性 | qmlRegisterType | qmlRegisterSingletonType |
|---|---|---|
| 实例化方式 | 每次 QML 声明时创建新实例 | 全局唯一实例 |
| 典型用途 | 可复用的 UI 组件、数据模型 | 全局服务、工具类、配置管理 |
| QML 中访问方式 | 通过声明元素(如 MyItem {}) | 直接通过类型名(如 MySingleton.method()) |
| 内存管理 | 由 QML 引擎管理 | 通常需手动管理(除非使用智能指针) |
| 线程安全性 | 实例独立,需自行处理线程安全 | 单例需考虑线程安全 |
qmlRegisterSingletonType<SystemModel>("SystemModel", 1, 0, "SystemModel",
[](QQmlEngine *engine, QJSEngine *jsEngine) -> QObject* {
(void)engine;
(void)jsEngine;
return &SYSTEM_MODEL;
}
);
qmlRegisterType<NetworkManager>("QtNetworkManager", 1, 0, "NetworkManager");
注册完毕后,qml就能识别你的model文件了。
这种是模块化的注册,所以需要在对应的.qml文件里导入
import SystemModel 1.0,
就能调用systemmodel里的函数了
setContextProperty
// setContextProperty 方式
engine.rootContext()->setContextProperty("confirmPopupModel", &CONFIRM_POPUP_MODEL);
这种是全局性的注册,qml端不用导入可以直接调用
// QML中直接使用,无需导入
Rectangle {
Component.onCompleted: {
confirmPopupModel.show() // 直接访问
}
}
区别

传输修改
model
信号直接来自qml文件,同时会经过model文件的修饰和处理,然后发出去。
在model中发送修改信号到Moonraker中,在modelhandletask.cpp的initConnection里添加:
// 添加了这一行就能实现控制了
// sigEditTargetLeftNozzleTemper 是 CameraManagerModel的 signal里的信号
// onHandleLeftTemperature 是 ModelHandleTask的槽函数,该函数需要在本页根据 Moonraker 里的json类型进行定义
connect(&CAMERA_MANAGER_MODEL, &CameraManagerModel::sigEditTargetLeftNozzleTemper, this, &ModelHandleTask::onHandleLeftTemperature, Qt::QueuedConnection);
message
在WebSocketThread.cpp的初始化函数中将moonraker的信息通过textMessageReceived函数传给websocketThread的onreciveMessage;
// WebSocketThread.cpp
connect(_webClient.get(), &QWebSocket::textMessageReceived, this, &WebSocketThread::onReciveMessage);
// 立刻激发出去
void WebSocketThread::onReciveMessage(const QString &message)
{
// qDebug() << "WebSocketThread: onWebsocketRecive" << message;
emit sigReciveMessage(message);
}
在mainctrl.cpp中再调用websocketThread的sigReciveMessage信号,修饰一番,再传入到MessageHandleTask的信号槽onReciveMessage中。
但是不知道为什么信号对象由_webClient转变成了_webClientTask.
// mainctrl.cpp
connect(_webClientTask.get(), &WebSocketThread::sigReciveMessage, _messageTask.get(), &MessageHandleTask::onReciveMessage, Qt::QueuedConnection);
MessagehandleTask中的onReciveMessage是专门处理Moonraker信息并且分配到各个model中,让model去刷新界面
至此,通信流程结束。
1646

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



