VS2026+QT6.9运行时描述类QMetaObject::QMetaMethod--invokeMethod用法
简介QMetaObject::invokeMethod是 Qt 框架中跨线程调用对象槽函数 / 成员函数的标准、安全方法也是 Qt 元对象系统最核心的功能之一。简单说它可以让你在任意线程安全调用另一个线程中 QObject 对象的成员函数自动处理线程切换避免线程安全崩溃。核心作用跨线程调用主线程 ↔ 子线程 子线程 ↔ 子线程 互相调用对方对象的函数异步/同步调用可选择不等待返回异步、等待执行完成同步自动线程安全Qt 自动排队、调度无需手动加锁支持槽函数/普通成员函数只要函数被Q_INVOKABLE声明或为槽函数调用方式Qt::QueuedConnection异步调用立即返回 跨线程用Qt::DirectConnection 直接调用直接在当前线程执行不跨线程Qt::BlockingQueuedConnection 同步阻塞调用当前线程等待函数执行完毕才继续 同线程用会死锁如果想要拿到返回值的话必须用这种方式Qt::AutoConnection 自动判断同线程 直接跨线程 队列最常用默认值常用写法1、无参数、无返回值异步跨线程推荐// 目标对象worker函数doWork() QMetaObject::invokeMethod(worker, doWork, Qt::QueuedConnection);2、带参数用 Q_ARG 包装// 函数void setValue(int value, QString name); QMetaObject::invokeMethod( worker, setValue, Qt::QueuedConnection, Q_ARG(int, 100), // 第1个参数 Q_ARG(QString, test) // 第2个参数 );3、带返回值用Q_RETURN_ARG接收// 函数int calculate(int a, int b); int result 0; QMetaObject::invokeMethod( worker, calculate, Qt::BlockingQueuedConnection, // 必须阻塞才能拿到返回值 Q_RETURN_ARG(int, result), // 接收返回值 Q_ARG(int, 10), Q_ARG(int, 20) ); qDebug() 结果 result; // 30必要条件1、目标对象必须是QObject子类2、函数必须满足其中一种声明为slots槽函数用Q_INVOKABLE 修饰class Worker : public QObject { Q_OBJECT public slots: void doWork(); // 可以调用 int calculate(int a, int b); // 可以调用 public: Q_INVOKABLE void test(); // 可以调用 void normalFunc(); // ❌ 不能调用 };3、目标对象所在线程必须运行Qt事件循环exec()默认启动、重写run要启动QThread thread; thread.start(); // 默认 run() 会调用 exec() → 有事件循环 void run() override { init(); exec(); // ✅ 手动启动事件循环 }4、参数类型必须是Qt元系统已知类型自定义类型需qRegisterMetaType// C类型 bool int, unsigned int long, unsigned long long long, unsigned long long float, double char* // Qt核心类型常用 QString QByteArray QPoint, QPointF QSize, QSizeF QRect, QRectF QColor QFont QPixmap (不能跨线车只能在主线程使用子线程使用QImage) QImage QDateTime, QTime, QDate QUrl QVariant // Qt容器 QListint QListQString QVectorint QVectorQString QMapQString, int QHashQString, QString std::vectorint std::listQString使用场景1、子线程更新 UI主线程操作 UI// 子线程中 → 安全调用主线程 UI 函数 QMetaObject::invokeMethod(label, setText, Qt::QueuedConnection, Q_ARG(QString, 任务完成));2、主线程控制子线程启停// 启动子线程工作 QMetaObject::invokeMethod(worker, startWork, Qt::QueuedConnection); // 停止工作 QMetaObject::invokeMethod(worker, stopWork, Qt::QueuedConnection);3、跨线程获取子线程计算结果// 阻塞等待子线程计算完成并返回结果 QString data; QMetaObject::invokeMethod(worker, getData, Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, data));4、跨线程启动和停止定时器public slots: // 必须写成 slot 或 Q_INVOKABLE才能被 invokeMethod 调用 void startTimer(int ms 1000) { m_timer-start(ms); qDebug() 定时器启动线程 QThread::currentThread(); } // 启动定时器跨线程调用 QMetaObject::invokeMethod( worker, startTimer, // slot 函数名 Qt::QueuedConnection, Q_ARG(int, 500) // 500ms 触发一次 );代码详解 QMetaMethod-查询对象的函数方法 QMetaProperty是查询对象的属性#include QtWidgetsApplication3.h QtWidgetsApplication3::QtWidgetsApplication3(QWidget* parent) : QMainWindow(parent) { ui.setupUi(this); thread new QThread(this); worker new Worker(this); // 这里传递主窗口指针 使用元对象系统QMetaObject::invokeMethod worker-moveToThread(thread); connect(thread, QThread::finished, worker, QObject::deleteLater); connect(thread, QThread::finished, thread, QThread::deleteLater); thread-start(); // 子线程读主线程私有成员值 connect(ui.pushButton, QPushButton::clicked, worker, Worker::getname); } // 析构安全退出兵删除子线程 QtWidgetsApplication3::~QtWidgetsApplication3() { if (thread thread-isRunning()) { thread-quit(); thread-wait(); thread nullptr; worker nullptr; } } // 获取私有成员变量的值 QString QtWidgetsApplication3::getUsername() const { return m_str; } // 子线程构造 Worker::Worker(QtWidgetsApplication3* mainWin) { m_mainWin mainWin; qDebug() Worker::Worker() QThread::currentThread(); } // 子线程析构 Worker::~Worker() {} // 子线程获取主线程的私有成员值 void Worker::getname() { const QMetaObject* mainWin m_mainWin-metaObject(); for (int i 0; i mainWin-methodCount(); i) { QMetaMethod m mainWin-method(i); qDebug() m.methodSignature(); } bool ok QMetaObject::invokeMethod(m_mainWin, getUsername, Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, m_str)); if (ok) { qDebug() Worker::getname() m_str; } }#pragma once #include QtWidgets/QMainWindow #include ui_QtWidgetsApplication3.h #include QThread #include QObject #include QMetaMethod class Worker; class QtWidgetsApplication3 : public QMainWindow { Q_OBJECT public: QtWidgetsApplication3(QWidget* parent nullptr); ~QtWidgetsApplication3(); QThread* thread; Worker* worker; // 获取私有成员变量的值只读访问 通过 Q_INVOKABLE 修饰符修饰 Q_INVOKABLE QString getUsername() const; //public slots: // // 获取私有成员变量的值只读访问 槽函数slots可以不写 Q_INVOKABLE 修饰符 // QString getUsername() const; private: Ui::QtWidgetsApplication3Class ui; QString m_str 20260512; }; // 线程类 class Worker : public QObject { Q_OBJECT public: explicit Worker(QtWidgetsApplication3* mainWin); // 这里要接受主窗口的指针 ~Worker(); private: QtWidgetsApplication3* m_mainWin; QString m_str; public slots: void getname(); };