8
votes

The signal/slot mechanism in Qt, is a static mechanism. The classes have to be preprocessed by the moc compiler.
Now I want to create signals and slots dynamically at run-time.
I already have a working solution, but it feels to me like a hack, although I am using publicly available methods.
This is the code for dynamic slots:

bool DynamicQObject::connectDynamicSlot(const QString &objectName, QObject *pSourceObject, QMetaMethod signalMethod)
{
    QByteArray slotName = signalMethod.name().prepend("on").append("(");
    QStringList parameters;
    for (int i = 0, j = signalMethod.parameterCount(); i < j; ++i)
    {
        parameters << QMetaType::typeName(signalMethod.parameterType(i));
    }
    slotName.append(parameters.join(",")).append(")");
    QByteArray theSignal = QMetaObject::normalizedSignature(signalMethod.methodSignature().constData());
    QByteArray theSlot = QMetaObject::normalizedSignature(slotName);
    if (!QMetaObject::checkConnectArgs(theSignal, theSlot))
    {
        return false;
    }

    int signalId = pSourceObject->metaObject()->indexOfSignal(theSignal);
    if (signalId < 0)
    {
        return false;
    }

    int slotId = slotIndices.value(theSlot, -1);
    if (slotId < 0)
    {
        slotId = slotList.size();
        slotIndices[theSlot] = slotId;
        slotList.append(createSlot(theSlot, objectName, signalMethod));
    }

    return QMetaObject::connect(pSourceObject, signalId, this, slotId + metaObject()->methodCount());
}

As you can see, I make intensive use of the QMetaObject, and particularly the index of the slots (method count).
The code for dynamic signals is comparable.

Now my question is: how future proof is this solution, especially because I assume that the index must be at least one bigger than the methodCount()?

2
I think if you explained a concrete scenario where this is useful for you, people might give you better alternatives than this to implement it.Mat
@Mat You have a point, but I only want to know whether this implementation is future proof. Regarding a scenario: I am working on a pubsub platform, where events can be dynamically integrated. The code above is, a.o. used in a C++ socket.io client. With this implementation it is possible to execute the following: socketIoObject.connect("customEvent", &socketIoObject, [=](Event e){ process event }Kurt Pattyn
You should share the architecture. Some description would be better than code. So far all I see is that you're connecting to a non-existent slot that only exists in your own list within the DynamicQObject. What's important is how you integrate this with the metacall machinery. Connecting events to lambdas or event emission can be done without need for dynamic signals/slots. You gain nothing by repurposing QObject::connect. You should simply create your own method for that, IMHO.Kuba hasn't forgotten Monica
You may wish to look at this Qt Quarterly 16 article. It deals exactly with your issue. It still works in Qt 5.Kuba hasn't forgotten Monica

2 Answers

2
votes

Now my question is: how future proof is this solution, especially because I assume that the index must be at least one bigger than the methodCount()?

It should work as of now.

As for future proof... may be. The snippet is using unsupported features which means those might break at any point in the future. It is likely though it will continue working.

0
votes

As a separate option, if all your things are very similar in nature (like in a vector or something), consider connecting to a lambda function. eg:

QObject::connect(iter->checkbox, &QCheckBox::stateChanged,
                [&, iter->startup_status](int new_val) {
                    if (new_val == Qt::CheckState::Checked) {
                        startup_status = true;
                    } else {
                        startup_status = false;
                    }
                });

where iter is a struct/class that has public fields

QCheckBox *checkbox;
bool startup_status;

by this method, it is possible to have a variable number of very similar "slots" (which aren't actually slots, but act like slots)