如何在Qt中创建动态信号和槽?

9
在Qt中,信号/槽机制是一种静态机制。这些类必须由moc编译器预处理。
现在我想在运行时动态创建信号和槽。
我已经有了一个可用的解决方案,但它感觉像个hack,尽管我使用的是公开可用的方法。
下面是动态槽的代码:
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());
}

正如您所看到的,我大量使用QMetaObject,特别是槽的索引(方法计数)。

动态信号的代码也是类似的。

现在我的问题是:这种解决方案的未来性有多高,特别是因为我假设索引必须至少比methodCount()大1?


1
我认为如果您解释了一个具体的场景,说明这对您有用,人们可能会给您提供比这更好的替代方案来实现它。 - Mat
@Mat 你说得有道理,但我只想知道这个实现是否具备未来的可扩展性。关于场景:我正在开发一个pubsub平台,在这个平台上事件可以动态集成。上面的代码是在C++ socket.io客户端中使用的。通过这个实现,可以执行以下操作:socketIoObject.connect("customEvent", &socketIoObject, [=](Event e){ process event } - Kurt Pattyn
你应该分享架构。一些描述比代码更好。到目前为止,我所看到的是,你正在连接到一个不存在的槽,该槽仅存在于DynamicQObject中的自己列表中。重要的是你如何将其与元调用机制集成。将事件连接到lambda表达式或者通过事件发射可以在不需要动态信号/槽的情况下完成。通过重新使用 QObject::connect并没有任何收获。 我认为,你应该简单地为此创建自己的方法。 - Kuba hasn't forgotten Monica
2
你可能希望查看这篇Qt Quarterly 16文章。它正好涉及到你的问题。在Qt 5中仍然有效。 - Kuba hasn't forgotten Monica
QtQuarterly 16文章的存档链接为https://web.archive.org/web/20150525024150/http://doc.qt.digia.com/qq/qq16-dynamicqobject.html。一个可能的用例是实现脚本语言-Qt的Python绑定显然有一些方法可以动态地实现这一点。 - DavidW
2个回答

2

现在我的问题是:这个解决方案有多少未来性,特别是因为我假设索引必须至少比methodCount()大1个?

目前应该可以正常工作。

至于未来的可靠性...可能吧。这段代码正在使用不受支持的功能,这意味着它们可能在未来的任何时间点被破坏。但很可能会继续工作。


0
作为一种单独的选择,如果您手头的所有事物在本质上非常相似(比如在一个向量中),可以考虑连接到一个lambda函数。例如:
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;
                    }
                });

其中iter是一个具有公共字段的结构体/类

QCheckBox *checkbox;
bool startup_status;

通过这种方法,可以拥有一系列变量数量非常相似的“插槽”(实际上并不是真正的插槽,但起到了类似插槽的作用)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接