QObject generic signal handler

后端 未结 3 1951
没有蜡笔的小新
没有蜡笔的小新 2021-02-02 03:24

(With \"signal handler\" I mean slots, not handlers for POSIX signals.)

I need to \"connect\" (probably not using QObject::connect directly)

3条回答
  •  旧时难觅i
    2021-02-02 04:08

    I was looking for a generic signal handler for the same reason, i.e. forwarding signal calls via RPC. There is a very interesting and detailed description of the QObject-QMetaObject magic in a QtDevDays presentation. In particular, they also describe the desire to inspect generic signals for debugging or interfacing with scripting languages - so this is a perfect read.

    Long story short: Your solution was to modify qt_static_metacall in the moc code. (Now in Qt5?) The same thing can be achieved by subclassing your QObject based class and overriding qt_metacall, for example:

    class QRpcService : public QRpcServiceBase
    {
    public:
        explicit QRpcService(QTcpServer* server, QObject *parent = 0);
        virtual ~QRpcService();
    
        virtual int qt_metacall(QMetaObject::Call, int, void**);
    private:
        static int s_id_handleRegisteredObjectSignal;
    };
    

    The magic capture-all-slot is just a dummy method defined in the base class (here void handleRegisteredObjectSignal()) that takes nothing and does nothing. I query its meta-method-id in the constructor and store it as static int to avoid searching for it every time.

    Within this custom metacall handler you intercept the calls to your magic-capture-all slot and inspect the sender object and signal. This provides all the type information required to convert the void** arguments to a QVariant list

    int QRpcService::qt_metacall(QMetaObject::Call c, int id, void **a)
    {
        // only handle calls to handleRegisteredObjectSignal
        // let parent qt_metacall do the rest
        if (id != QRpcService::s_id_handleRegisteredObjectSignal)
            return QRpcServiceBase::qt_metacall(c, id, a);
    
        // inspect sender and signal
        QObject* o = sender();
        QMetaMethod signal = o->metaObject()->method(senderSignalIndex());
        QString signal_name(signal.name());
    
        // convert signal args to QVariantList
        QVariantList args;
        for (int i = 0; i < signal.parameterCount(); ++i)
            args << QVariant(signal.parameterType(i), a[i+1]);
    
        // ...
        // do whatever you want with the signal name and arguments
        // (inspect, send via RPC, push to scripting environment, etc.)
        // ...
    
        return -1;
    }
    

    I just handled everything within this method, but you could also re-emit all the information that was gathered in another signal and attach to that at runtime.

    If anyone is interested, I also set up a repository with my solution here.

提交回复
热议问题