20

I have got a super class Common, which inherits from QObject. Then I have got a class Item, which inherits from Common.

Common.h

class Common : public QObject {
    Q_OBJECT

public:
    // some methods
};

Item.h

class Item : public Common {
    Q_OBJECT

public:
    // some methods
    void test(QString value);
};

Item.cpp

void Item::test(QString value) {
    qDebug() << value;
}

I want to use QMetaObject::invokeMethod to dynamically call a function. So I implemented a test function in the Item class, which takes exactly one string.

Item* item = new Item();
QMetaObject::invokeMethod(item, "test", Qt::DirectConnection, Q_ARG(QString, "1234"));

This does not work. I get the following error: QMetaObject::invokeMethod: No such method Common::test(QString), which is perfectly okay and fine, because the Common class has no test function.

How can I tell QMetaObject::invokeMethod, that it should call the method from the Item class?

Niklas
  • 23,674
  • 33
  • 131
  • 170
  • Does `class Item` have `Q_OBJECT` macro? It's required in order to make slots known to the meta-object system. Adding slots is still possible, but they will only be normal functions then. Also, the function needs to be a slot (or a `Q_INVOKABLE` method) in the first place. – leemes Jul 08 '14 at 22:25
  • No it hasn't. I added it, but still get the error. Should I edit my question and put the necessary source code in it or do you have another hint? – Niklas Jul 08 '14 at 22:30
  • When you add the macro, re-run qmake. It needs to scan your files for the macro in order to know that it needs to run `moc` on it. Another pitfall of Qt... ;) – leemes Jul 08 '14 at 22:32
  • If that didn't help, yes, some more code could help. – leemes Jul 08 '14 at 22:33
  • I edited my question and inserted the necessary code. – Niklas Jul 08 '14 at 22:37

1 Answers1

36

QMetaObject::invokeMethod can only invoke methods known to the Qt meta object system. These are slots and "invokable" functions, the latter being functions with the keyword Q_INVOKABLE before them.

So either write:

class Item : public Common {
    Q_OBJECT

public slots:
    // ^^^^^
    void test(QString value);
};

or:

class Item : public Common {
    Q_OBJECT

public:
    Q_INVOKABLE void test(QString value);
    //^^^^^^^^^
};
leemes
  • 44,967
  • 21
  • 135
  • 183
  • `Q_INVOKABLE void test(QString value);` did it for me. Thank you! – Niklas Jul 08 '14 at 22:41
  • 1
    @Niklas Yes, I added it in an edit :) I prefer `Q_INVOKABLE` over slots if the function is never used in a signal-slot connection. But for a lot of functions, just saying `public slots:` is less typing :) – leemes Jul 08 '14 at 22:42
  • What if i use `invokeMethod()` on a method of an instance of Qt class, which i can't change to be slot? In my case it looks like this: `QMetaObject::invokeMethod(scene, "addItem", Qt::BlockingQueuedConnection, Q_ARG(QGraphicsItem*, dynamic_cast(currentPixmap)));` Is there a way? – George Dec 05 '19 at 11:58