PDA

View Full Version : Problems with signals and slots in derived class



ittod
20th May 2013, 12:19
Hey, everyone!
I've been searching the web about my problem and found some strange solutions, but they didn't work. Well, let me explain the situation first.
I'm using Qt Creator (2.4.1, based on Qt 4.8.0(64 bit)) on Linux Mint 13. Writing some kind of a simplest "Worms" clone, using QGraphicsView, QGraphicsScene and QGraphicsItems.

Created a class Worm, that inherits from QGraphicsItem. (I'll explain why Q_OBJECT is commented out later)

class Worm : public QGraphicsItem
{
// Q_OBJECT

public:
Worm();
Worm (QGraphicsPathItem * argWorld);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void advance(int phase);

private:
QGraphicsPathItem * world;

signals:
void hasTouchedTheGround();
};
I've already drawn the random "world" in my custom QGraphicsScene constructor using QGraphicsPathItem, so I wanted to add a Worm in some spot in my scene and let it fall to the ground. Simple.

addItem(world);
addItem(myworm);
// let the worm fall down till collision
timer = new QTimer(this);
if (!myworm->collidesWithItem(world)) {
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(advance()));
QObject::connect(myworm, SIGNAL(hasTouchedTheGround()), timer, SLOT(stop()));
}
timer->start(50);
And here comes the compile error:

myscene.cpp: In constructor 'MyScene::MyScene(QObject*)':
myscene.cpp:48:84: error: no matching function for call to 'MyScene::connect(Worm*&, const char*, QTimer*&, const char*)'
[bla-bla-bla, candidates etc]
/usr/include/qt4/QtCore/qobject.h:204:17: note: no known conversion for argument 1 from 'Worm*' to 'const QObject*'
That was a big surprise. As far as I know, QGraphicsItem has QObject somewhere among his parents.
I found a solution here (http://qt-project.org/forums/viewthread/15378). It was said, that a compiler "does not know", that my class is derived from QObject, and the solution is as simple as adding #include "worm.h" to myscene.cpp file.
Didn't work. *deep sigh* so I had to add a cast (QObject*).
Okay, then I added emission of my signal to worm.cpp. And here's the magic:

myWormApp/worm.cpp:23: undefined reference to `Worm::hasTouchedTheGround()'
Whoa! So, compiler still doesn't understand, that Worm is derived from QObject. Okay, I thought that a Q_OBJECT would help. So I added the macro, right-clicked on the project, ran qmake then ReBuild.
Build returned 14 (fourteen!) errors. :mad: The output is quite long, so here's just a few lines from it:

moc_worm.cpp: In static member function 'static void Worm::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)':
moc_worm.cpp:47:42: error: invalid static_cast from type 'QObject*' to type 'Worm*'
moc_worm.cpp: At global scope:
moc_worm.cpp:61:8: error: 'staticMetaObject' is not a member of 'QGraphicsItem'
/usr/include/qt4/QtCore/qobject.h: In member function 'virtual const QMetaObject* Worm::metaObject() const':
/usr/include/qt4/QtCore/qobject.h:320:33: error: 'QScopedPointer<QObjectData> QObject::d_ptr' is protected
I've gone crazy and decided to inherit from QObject:

class Worm : public QGraphicsItem, public QObject
qmake, rebuild. Got only 3 errors:

moc_worm.cpp:61:8: error: 'staticMetaObject' is not a member of 'QGraphicsItem'
moc_worm.cpp: In member function 'virtual void* Worm::qt_metacast(const char*)':
moc_worm.cpp:81:12: error: 'qt_metacast' is not a member of 'QGraphicsItem'
moc_worm.cpp: In member function 'virtual int Worm::qt_metacall(QMetaObject::Call, int, void**)':
moc_worm.cpp:86:11: error: 'qt_metacall' is not a member of 'QGraphicsItem'
moc_worm.cpp: In member function 'virtual void* Worm::qt_metacast(const char*)':
moc_worm.cpp:82:1: warning: control reaches end of non-void function [-Wreturn-type]
make: *** [moc_worm.o] Error 1

Is there any solution? I can't understand why nothing works, it seems so simple and clear.

Added after 6 minutes:

Sorry for double-post, I got a short update.
For some random reason I decided to change the inheritance order to:
class Worm : public QObject, public QGraphicsItem

Now compiler returned only one warning:

worm.h:24: Warning: Class Worm implements the interface QGraphicsItem but does not list it in Q_INTERFACES. qobject_cast to QGraphicsItem will not work!

But still I can't understand what is happening, what do all these strange errors mean?

rawfool
20th May 2013, 12:21
Uncomment the macro Q_OBJECT in your class Worm and rebuild your project.

ittod
20th May 2013, 12:22
Uncomment the macro Q_OBJECT in your class Worm and rebuild your project.
I already did that. That caused 14 errors.

lanz
21st May 2013, 07:37
If you want signals and slots, you should inherit QObject. QGraphicsItem doesn't inherit it.
In your case you should inherit QGraphicsObject, which is already inherits QGraphicsItem and QObject.

http://qt-project.org/doc/qt-4.8/qgraphicsobject.html
(And of course uncomment Q_OBJECT macro).

wysota
21st May 2013, 08:17
I already did that. That caused 14 errors.

Rerun qmake.

ittod
21st May 2013, 16:31
If you want signals and slots, you should inherit QObject. QGraphicsItem doesn't inherit it.
In your case you should inherit QGraphicsObject, which is already inherits QGraphicsItem and QObject.

http://qt-project.org/doc/qt-4.8/qgraphicsobject.html
(And of course uncomment Q_OBJECT macro).

Thanks a lot, I didn't know about that class. That's just what I needed. Also it's built-in signals helped me a lot.


Rerun qmake.
I did that, didn't help.
Now the problem is solved thanks to lanz. Causes of the problem:
1) QGraphicsItem doesn't inherit QObject, so it doesn't support signals & slots.
2) For some reason, the order of inheritance mattered. So when I wrote "class Worm : public QGraphicsItem, public QObject", the project didn't compile and returned errors. All errors disappeared just when I changed the inheritance that way: "class Worm : public QObject, public QGraphicsItem". That's really weird.

wysota
21st May 2013, 22:16
All errors disappeared just when I changed the inheritance that way: "class Worm : public QObject, public QGraphicsItem". That's really weird.

It's documented.