Search code examples
c++qtsignalssignals-slotsslot

Qt: connecting signals and slots from text


How would I connect a signal and slot of 2 objects when the object names, signals, and slots are all specified in a text file?

Getting the right objects names isn't an issue, since I can easily loop through an array and compare the names to the spot in the file, but there has to be some sort of way where I can return the signal and slot from the file and use it in the connect function, like:

connect(rtnObj1(line),SIGNAL(rtnSignal(line)),rtnObj2(line),SLOT(rtnSlot(line)));

where rtn functions return the object name/signal/slot, and "line" is the current QString line from the file.

The only way I know of is by literally coding in every single combination and comparing QStrings with if statements, but that would be incredibly tedious, as the amount of combinations would be incredibly high.

Note: Here's a simplified example demonstrating essentially how this issue exists.

Frame 1: 4 QComboBoxes. The first and third hold object names, the second holds signals, the fourth holds slots. Every item is of course a QString within these lists. Hitting a button appends a new line to a file, writing the text selected from each box.

Frame 2: Has already has the required objects. Reading the file, it would match the objects defined in the list against the ones already created, and connect them as the file describes.

It's easy enough to create an object based on the data a file holds, but how would one create/pull a signal and a slot from a file?

Edit: Unless, is one able to connect like this?

connect(objectA, "", objectB, "");

Because I just found out that my code will compile like that, however whenever I try putting in the slot or signal names I just get an error like:

QObject::connect: Use the SIGNAL macro to bind Tile::clicked


Solution

  • Your problem is easily solvable with one of the following static QObject::connect() method:

    QMetaObject::Connection QObject::connect(
        const QObject *sender, const QMetaMethod &signal,
        const QObject *receiver, const QMetaMethod &method,
        Qt::ConnectionType type = Qt::AutoConnection)
    

    First of all, you need pointers to sender and receiver objects. There are several ways how you can store an object pool. I would suggest to keep all objects in QHash:

    QHash<QString, QObject *> m_objects; // I use QObject as a generic example
    

    Now, it's possible to find a pointer to any object for connecting in an efficient way.

    The next step would be obtaining QMetaMethod objects for sender's signal and receiver's slot from corresponding QMetaObject objects. Use QObject::metaObject() QMetaObject instances.

    Here's the complete code of a function which connects two object using only string parameters:

    void dynamicConnect(const QString &senderName, const QString &signalName,
                        const QString &receiverName, const QString &slotName)
    {
        QObject *emitter = m_objects.value(senderName);
        int index = emitter->metaObject()
                ->indexOfSignal(QMetaObject::normalizedSignature(qPrintable(signalName)));
        if (index == -1) {
            qWarning("Wrong signal name!");
            return;
        }
        QMetaMethod signal = emitter->metaObject()->method(index);
    
        QObject *receiver = m_objects.value(receiverName);
        index = receiver->metaObject()
                ->indexOfSlot(QMetaObject::normalizedSignature(qPrintable(slotName)));
        if (index == -1) {
            qWarning("Wrong slot name!");
            return;
        }
        QMetaMethod slot = receiver->metaObject()->method(index);
    
        QObject::connect(emitter, signal, receiver, slot);
    }