2012-12-03 91 views
3

我试图破解Qt的信号和插槽,并且遇到了QMetaType :: invokeMethod无法将指针参数正确传递到被调用的插槽的问题。Qt - 调用将自定义指针作为参数的插槽

call(QObject *receiver, const char *slot, const QList<QGenericArgument> &args) 
{ 
    const QMetaObject *meta = receiver->metaObject(); 
    bool success = meta->invokeMethod(receiver, slot, 
      args.value(0, QGenericArgument()), 
      args.value(1, QGenericArgument()), 
      args.value(2, QGenericArgument()), 
      ... 
      args.value(9, QGenericArgument())); 
} 

然后,我把它叫做以下方式:

MyReceiver *receiver; 
MyObject *myObject; 

call(receiver, "mySlot", QList<QGenericArgument>() << Q_ARG(MyObject *, myObject)); 

哪里class MyObject : public QObject { ... }。我也做Q_DECLARE_METATYPE(MyObject *)qRegisterMetaType<MyObject *>("MyObject *")

什么情况是,接收器上的插槽被调用,但随着参数的值总是0不管我传递给call(...)Q_ARG

出于好奇我看着接收器的自动生成的MOC文件,发现槽用下面的代码调用:

void MyReceiver::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) 
{ 
    if (_c == QMetaObject::InvokeMetaMethod) { 
     Q_ASSERT(staticMetaObject.cast(_o)); 
     MyReceiver *_t = static_cast<MyReceiver *>(_o); 
     switch (_id) { 
     case 0: _t->mySlot((*reinterpret_cast< MyObject*(*)>(_a[1]))); break; 
     default: ; 
     } 
    } 
} 

事实证明的_a[1]值负有正确地址3210。但reinterpret_cast将它变成0

现在我有以下问题:

1)如何以编程方式调用插槽,并确保该指针参数是否正确传递给插槽? 2)这个*reinterpret_cast< MyObject*(*)>(_a[1])是什么意思?什么额外括号(*)的意思,以及如何解释这段代码?

+0

查看SLOT()宏。我对我来说有一段时间了,但这可能会回答你的问题。 – dmaij

+0

'invokeMethod'允许您仅通过名称和参数值调用一个插槽,而不提供完整的签名。它工作正常,但不适用于非标准参数类型,至少对我来说... –

+0

这应该工作。您的call()实现看起来并不实际地转发参数(或者这只是您的示例代码不正确?)。如果直接调用QMetaObject :: invokeMethod,它是否工作? _a [1]是一个指向指针的指针,因此reinterpret_cast中的(*)。 –

回答

0

好的,我想我觉得它为什么不工作...... Q_ARG只会创建一个指向我的指针并存储前者。我没有提到call函数是Task调用的一部分,它意味着稍后调用一个插槽 - 当包装到Q_ARG中的值已超出范围时。基本上Q_ARG只维护对参数对象的弱引用。