如何在QObject :: connect中使用QMetaMethod

时间:2010-05-09 22:21:48

标签: c++ qt qt4

我有两个QObject子类实例和两个QMetaMethod信号实例,其中一个对象和另一个对象中的插槽。我想把这个信号和插槽相互连接起来。

我查看了qobject.h文件,发现SIGNAL()和SLOT()宏只是在方法签名的开头添加“1”或“2”字符,所以它看起来应该可以将相同的字符添加到QMetaMethod :: signature()返回的字符串的开头,但这种方法依赖于一些未记录的工具包内部,并且可能随时被新版本的Qt破坏。

有人知道通过QMetaMethod反射表示连接信号和插槽的可靠方法吗?

编辑: 我在Qt问题跟踪器中创建了建议: https://bugreports.qt.io/browse/QTBUG-10637 如果有人对此功能感兴趣,您可以在那里投票支持此票。

4 个答案:

答案 0 :(得分:14)

自Qt 4.8.0起已修复:

https://bugreports.qt.io/browse/QTBUG-10637

假设我们有一个QObject * m_subject,并希望将属性的change-notification信号连接到propertyChanged()槽:

const QMetaObject* meta = m_subject->metaObject();
QMetaProperty prop = meta->property(meta->indexOfProperty("myProperty"));
if (prop.hasNotifySignal()) {
    QMetaMethod signal = prop.notifySignal();
    QMetaMethod updateSlot = metaObject()->method(
        metaObject()->indexOfSlot("propertyChanged()"));
    connect(m_subject, signal, this, updateSlot);
}

我成功地使用它来创建一个QWidget子类,它查找任何QObject的所有属性,并为每个QObject创建一个QLineEdit,并通过连接在相应的属性更改时保持QLineEdit更新。 (因为我没有找到将propertyID值传递给propertyChanged()的方法,但有必要创建QLineEdit的子类并在那里实现propertyChanged()。QSignalMapper没有帮助,因为所有属性都在同一个对象。)

答案 1 :(得分:1)

看起来没有办法让它在不依赖内部实现的情况下工作。如果我是你,我会向Qt bug tracker提交功能请求,编写一个模仿当前行为SIGNAL / SLOT宏的代码,并添加在SIGNAL / SLOT行为发生变化时失败的单元测试。

对于您尝试解决的问题,可能有一个更简单的解决方案:描述您在没有任何实现细节的情况下究竟要做什么。

答案 2 :(得分:0)

如果签名方法在QMetaMethod中公开,那么结果不应该被巨魔打破并且使用它是安全的(文档在使用QMetaMethod :: signature方法时没有说明“危险”)。我想你可以安全地使用它。只是为了确定,你现在使用的是什么版本的Qt?

答案 3 :(得分:0)

感谢MBack,我现在使用元方法将视图动态连接到MVVM或MVC模式的模型属性。 为了遵守DRY,需要以下样板:

 void myObject::myconnect(QObject* sender, std::string signalName, QObject* receiver, std::string slotName)
 {
    int sigIdx = sender->metaObject()->indexOfSignal(signalName.c_str());
    auto signal = sender->metaObject()->method(sigIdx);
    int slotIdx = receiver->metaObject()->indexOfSlot(slotName.c_str());
    auto slot = receiver->metaObject()->method(slotIdx);
    connect(sender,signal,receiver,slot);
 }

void Form_IVConfiguration::connectProperty(QObject* sender, std::string propName, QObject* receiver, std::string slotName)
{
   int sigIdx = sender->metaObject()->indexOfProperty(propName.c_str());
   auto signal = sender->metaObject()->property(sigIdx ).notifySignal();
   int slotIdx = receiver->metaObject()->indexOfSlot(slotName.c_str());
   auto slot = receiver->metaObject()->method(slotIdx);
   return connect(sender, signal, receiver, slot);
}