QMetaObject之invokeMethod说明和使用

来源:互联网 发布:jq 将数组导出excel 编辑:程序博客网 时间:2024/05/01 09:38
 

QMetaObject之invokeMethod 点滴记录(有时间在看看)

分类: QT编程
qtsemaphoreconstructorobjectsignalfunction

目录(?)[+]

QMetaObject之invokeMethod 点滴记录
2010-10-18 16:53

起源

C++ GUI Qt4 编程 一书多线程部分提到invokeMethod的用法

QMetaObject::invokeMethod(label, SLOT(setText(const QString&)), Q_ARG(QString, "Hello"));

而 Qt Manual 中介绍却是

  • You only need to pass the name of the signal or slot to this function, not the entire signature. For example, to asynchronously invoke the animateClick() slot on a QPushButton, use the following code:

QMetaObject::invokeMethod(pushButton, "animateClick");

这可怎么办?一个是官方的图书,一个是官方的Manual。是否意味着两种方式都可以呢,还是说Qt的早期版本用的是前者?

查 Qt4.7/Qt4.6/Qt4.5/Qt4.4/Qt4.3/Qt4.2/Qt4.1/Qt4.0 ,结果发现都没有提到前面的用法。是不是书的出错呢?网上搜一下:确实有人抱怨它不工作

测试

本着事实就是的精神,还是先写个程序测试一下:

#include <QtCore/QObject> #include <QtCore/QDebug> #include <QtCore/QCoreApplication>  class Test : public QObject {     Q_OBJECT public:     Test(QObject * parent):QObject(parent)     {         connect(this, SIGNAL(sig1(QString)), SLOT(slot1(QString)));         QMetaObject::invokeMethod(this, "sig1", Q_ARG(QString, "constructor"));     }     Q_INVOKABLE void method1(const QString& t)     {         qDebug()<<"from method:"<<t;     }  signals:     void sig1(const QString& t);  public slots:     void slot1(const QString& t)     {         qDebug()<<"from slot:"<<t;     }  }; #include "main.moc"  int main(int argc, char *argv[]) {     QCoreApplication a(argc, argv);     Test obj(0);     QMetaObject::invokeMethod(&obj, "slot1", Q_ARG(QString, "Hello"));     QMetaObject::invokeMethod(&obj, "method1", Q_ARG(QString, "Hello"));     QMetaObject::invokeMethod(&obj, SLOT(slot1(QString)), Q_ARG(QString, "Hello with SLOT"));     QMetaObject::invokeMethod(&obj, METHOD(method1(QString)), Q_ARG(QString, "Hello with METHOD"));     return a.exec(); }

确实如他人所说,SLOT这种用法不工作

from slot: "constructor" from slot: "Hello" from method: "Hello" QMetaObject::invokeMethod: No such method Test::1slot1(QString)(QString) QMetaObject::invokeMethod: No such method Test::0method1(QString)(QString)

源码

顺便看看源码吧

bool QMetaObject::invokeMethod(QObject *obj,                                const char *member,                                Qt::ConnectionType type,                                QGenericReturnArgument ret,                                QGenericArgument val0,                                QGenericArgument val1,                                QGenericArgument val2,                                QGenericArgument val3,                                QGenericArgument val4,                               QGenericArgument val5,                                QGenericArgument val6,                                QGenericArgument val7,                                QGenericArgument val8,                                QGenericArgument val9) {     if (!obj)         return false;      QVarLengthArray<char, 512> sig;     int len = qstrlen(member);     if (len <= 0)         return false;

生成函数原型字符串(从这儿可以看到书中方法不工作的原因)

    sig.append(member, len);     sig.append('(');      const char *typeNames[] = {ret.name(), val0.name(), val1.name(), val2.name(), val3.name(),                                val4.name(), val5.name(), val6.name(), val7.name(), val8.name(),                                val9.name()};      int paramCount;     for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) {         len = qstrlen(typeNames[paramCount]);         if (len <= 0)             break;         sig.append(typeNames[paramCount], len);         sig.append(',');     }     if (paramCount == 1)         sig.append(')'); // no parameters     else         sig[sig.size() - 1] = ')';     sig.append('\0');

在元对象系统中看该函数信息是否存在

    int idx = obj->metaObject()->indexOfMethod(sig.constData());     if (idx < 0) {         QByteArray norm = QMetaObject::normalizedSignature(sig.constData());         idx = obj->metaObject()->indexOfMethod(norm.constData());     }     if (idx < 0 || idx >= obj->metaObject()->methodCount()) {         qWarning("QMetaObject::invokeMethod: No such method %s::%s",                  obj->metaObject()->className(), sig.constData());         return false;     }

获得相应的 QMetaMethod,调用其 invoke 方法

    QMetaMethod method = obj->metaObject()->method(idx);     return method.invoke(obj, type, ret,                          val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); }

QMetaMethod::invoke

接着看看它的源码,首先:

* 如果指定了返回值,检查返回值的类型是否和QMetaMethod 的中的一致

if (returnValue.data()) {         const char *retType = typeName();         if (qstrcmp(returnValue.name(), retType) != 0) {             // normalize the return value as well             // the trick here is to make a function signature out of the return type             // so that we can call normalizedSignature() and avoid duplicating code             QByteArray unnormalized;             int len = qstrlen(returnValue.name());              unnormalized.reserve(len + 3);             unnormalized = "_(";        // the function is called "_"             unnormalized.append(returnValue.name());             unnormalized.append(')');              QByteArray normalized = QMetaObject::normalizedSignature(unnormalized.constData());             normalized.truncate(normalized.length() - 1); // drop the ending ')'              if (qstrcmp(normalized.constData() + 2, retType) != 0)                 return false;         }     }
  • 为了利用现有的代码来规范化这儿返回值的类型,这儿构造了一个函数_(typeOfReturn)

* 检查参数个数,传递的参数是否不少于需要的参数

* 检查Connection的类型,处理AutoConnection

// check connection type     QThread *currentThread = QThread::currentThread();     QThread *objectThread = object->thread();     if (connectionType == Qt::AutoConnection) {         connectionType = currentThread == objectThread                          ? Qt::DirectConnection                          : Qt::QueuedConnection;     }
  • 对于 直连的,直接调 metacall,它进而去调用对象的 qt_metacall

if (connectionType == Qt::DirectConnection) {         return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, methodIndex, param) < 0;
  • 对于 Queued 的连接,post 相应的事件,进而转到对象的event()函数中

if (connectionType == Qt::QueuedConnection) {             QCoreApplication::postEvent(object, new QMetaCallEvent(methodIndex,                                                                    0,                                                                    -1,                                                                    nargs,                                                                    types,                                                                    args));
  • 对于 bolckedqueued 的连接,使用了信号量

            QSemaphore semaphore;             QCoreApplication::postEvent(object, new QMetaCallEvent(methodIndex,                                                                    0,                                                                    -1,                                                                    nargs,                                                                    types,                                                                    args,                                                                    &semaphore));             semaphore.acquire();
0 0
原创粉丝点击