QT event subscription publication based on QMetaObject:InvokeMethod

Article directory


In QT, two controls of the same parent container need to communicate with each other. You can communicate with the slot function through signals or obtain the corresponding controls through pointers. When browsing gitee, bloggers find a code. Based on QMetaObject::InvokeMethod, it is very convenient to communicate among multiple containers.

1, QT QMetaObject::InvokeMethod

In QT, QMetaObject contains all metadata of QObject subclasses, that is, some description information of QObject information, such as signal and slot information and member functions unique to QT. Then, through the meta object system, we can query the class name, signals, slots, attributes, callable methods and other information of a derived class of QObject, and then use QMetaObject::invokeMethod() to call a method of QObject registered in the meta object system

1. function prototype

bool QMetaObject::invokeMethod(QObject *obj, const char *member, 
                            Qt::ConnectionType type, 
                            QGenericReturnArgument ret,
                            QGenericArgument val0 = QGenericArgument(nullptr), 
                            QGenericArgument val1 = QGenericArgument(), 
                            QGenericArgument val2 = QGenericArgument(), 
                            QGenericArgument val3 = QGenericArgument(), 
                            QGenericArgument val4 = QGenericArgument(),
                            QGenericArgument val5 = QGenericArgument(),
                            QGenericArgument val6 = QGenericArgument(), 
                            QGenericArgument val7 = QGenericArgument(),
                            QGenericArgument val8 = QGenericArgument(),
                            QGenericArgument val9 = QGenericArgument())

  2. Function introduction

In the above functions, there are 5 types

QObject *obj: pointer to the called object.

const char*member: refers to the method of calling object member variable.

Qt:: connectiontype type: refers to the method for connecting the object. You can determine whether to call synchronously or asynchronously here,

The default is Qt::AutoConnect.

QGenericReturnArgument ret: returns a value for the called member method.

QGenericArgument val0~val9: refers to the formal parameters passed in to the called function. Up to 10 exist

Note that the types to be called must be signals, slots, and types recognized by the Qt meta object system. If they are not signals and slots, you can use qRegisterMetaType() to register data types. In addition, use Q_INVOKABLE to declare a function, or call it correctly

Note: for details, see Qt invokeMethod asynchronous call - in the brief book overview program, we often call functions. If the called functions take a long time, synchronous calls will cause blocking of the main program. Qt provides a convenient function QMetaObject::invokeMethod to facilitate us to https://www.jianshu.com/p/c77e28a81708

2, Event subscription and publishing

From the above introduction, we know that as long as we get the pointer of the object, we can call the slot function in the object through invokeMethod, or be called by Q_INVOKABLE declares the member variable, and passes the data information to the called object through the following parameters.

Then we can use a function to subscribe to events. When subscribing, we pass the this pointer of this class and the name of the event to be subscribed, and then encapsulate a function to publish the event, which is used to deliver messages to the subscribers of the corresponding event. This function is similar to that of newspapers and subscribers. Different newspapers publish different newspapers in different societies, and different people will subscribe to different newspapers. Suppose that 10 people subscribe to the newspapers of newspaper a and 10 people subscribe to the newspapers of newspaper B, then when newspaper a publishes a new newspaper, subscribers to the newspapers of newspaper a can receive the newspapers published by newspaper a through email to obtain the news recorded by newspaper A. when newspaper B publishes a new newspaper, People who have subscribed to newspaper B can receive the newspapers published by newspaper B through email to obtain the news recorded by newspaper B.

1. event subscription

bool PSEventController::subscribe(QObject* listener, const QByteArray& eventName)
    QWriteLocker locker(&ps_Lock_);
    if (psEvents_pool_.contains(eventName)) {
        if (-1 != psEvents_pool_[eventName].indexOf(listener)) {
            ps_LastError_ = QString("This object is subscribed to this eventName");
            return false;
        return true;
    } else {
        psEvents_pool_.insert(eventName, { listener });
        return true;

When a class invokes event subscription, the first parameter passes in the object pointer of the class, and the second parameter is used to pass in the subscribed event name. Then, the subscriber pointer is saved for the publisher to post events, and the subscribed event name is used as the basis for the subscribed event name and the corresponding slot function name.         

2. event release

bool PSEventController::publish(const QByteArray& eventName, Qt::ConnectionType connectionType,
    QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3,
    QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7,
    QGenericArgument val8, QGenericArgument val9)
    QReadLocker locker(&ps_Lock_);
    if (!psEvents_pool_.contains(eventName)) {
        ps_LastError_ = QString("No objects subscribe to this eventName");
        return false;
    auto methodName = methodFormatting(eventName);
    QStringList errors;
    for (auto listener : psEvents_pool_[eventName]) {
        if (!listener)
        auto ret = QMetaObject::invokeMethod(listener, methodName, connectionType,
            val0, val1, val2, val3, val4, val5, val6, val7, val8, val9);
        if (!ret)
    if (errors.isEmpty())
        return true;
    ps_LastError_ = QString("%1 execution failed:[\n").arg(QString(eventName));
    for (auto& err : errors)
        ps_LastError_ += QString("%1;\n").arg(err);
    ps_LastError_ += "]\n";
    return false;

When a class publishes events through publish, the first parameter passed in is the name of the published event, and the second parameter is usually filled in autoConnect to be selected automatically. Then, if there is published content, the content to be published is passed in val0~val9. Then, the slot function corresponding to the event name of the subscriber will be called in all subscribers subscribing to the event, and the contents of val0~val9 will be sent to the subscriber through the subscriber's pointer and the corresponding slot function through invokeMethod.

3, Examples

        1. subscribe

Widget::Widget(QWidget* parent)
    : QWidget(parent)
    , ui(new Ui::Widget)

    PSEventController::subscribe(this, "showText");

void Widget::on_psEvent_showText(QString msg)

As shown in the above code, the widget subscribes to the event of showText, and the corresponding slot function is on_psEvent_showText(QString msg). When a publisher publishes a showText event and passes parameters, the widget will call the slot function and obtain QString type data,

        2. release

    PSEventController::publish("showText", Q_ARG(QString, text));

The publisher publishes the showText event through the appeal code and through Q_ARG indicates that the transfer parameter is of QString type and the data is text. According to my usage, containers, structs, and custom classes can all be passed as parameters.

The code was written by the last author of gitee, and the big brother code warehouse: https://gitee.com/feng_yan_yu/qt-pub-subhttps://gitee.com/feng_yan_yu/qt-pub-sub


Publishing and subscribing based on the above events can facilitate data transmission among multiple containers. For the same event, there can be multiple subscribers or publishers.

Tags: C++ Qt

Posted by EWaveDev on Wed, 01 Jun 2022 17:05:47 +0530