PDA

View Full Version : Problem emitting singal with object-pointer as argument



Shawn
3rd September 2007, 09:59
The code is as below,

class MyRectItem : public QObject, public QGraphicsRectItem
{
Q_OBJECT
public:
...
MyElement* pE;
signals:
void itemSelected(MyElement* pE);
};

class MyView : public QMainWindow
{
Q_OBJECT
public slots:
void toTreeWidget(MyElement* pE);
};

In myview.cpp,

MyRectItem *i = new MyRectItem(x, y, w, h);
QObject::connect(i, SIGNAL(itemSelected(pE)), this, SLOT(toTreeWidget(i->pE)));

Why this doesn't work ??
Does this have something to do with using the object-pointer as argument of signal?:confused:

marcel
3rd September 2007, 10:03
First use qRegisterMetaType to register the MyElement* type. This is required when passing custom types between signals and slots.

Second, when connecting signals and slots, don't pass the objects as arguments:


QObject::connect(i, SIGNAL(itemSelected(MyElement*)), this, SLOT(toTreeWidget(MyElement)));


When you emit the itemSelected signal you are responsible to pass the appropriate MyElement*.

Regards

Shawn
3rd September 2007, 10:14
First use qRegisterMetaType to register the MyElement* type. This is required when passing custom types between signals and slots.

Second, when connecting signals and slots, don't pass the objects as arguments:


QObject::connect(i, SIGNAL(itemSelected(MyElement*)), this, SLOT(toTreeWidget(MyElement)));


When you emit the itemSelected signal you are responsible to pass the appropriate MyElement*.

Regards

I did what u suggested,

qRegisterMetaType<MyElement>("MyElement");


error C2512: 'MyElement' : no appropriate default constructor available

Actually,

class MyElement
{
public:
MyElement(const QString &type)
:ElementType(type)
{
content.clear();
}

~MyElement(void) {}
}

BTW, the pE above was declared as MyElement*, which has already been pointer as your suggested:)

marcel
3rd September 2007, 10:55
Add right after the class, in the header: Q_REGISTER_METATYPE(MyElement*);
And next you should have:
qRegisterMetaType<MyElement*>("MyElement*");

I think... :)

Regards

danadam
3rd September 2007, 12:15
error C2512: 'MyElement' : no appropriate default constructor available


Have you tried adding default constructor?

Shawn
3rd September 2007, 12:51
Add right after the class, in the header: Q_REGISTER_METATYPE(MyElement*);
And next you should have:
qRegisterMetaType<MyElement*>("MyElement*");

I think... :)

Regards

What do you mean by "right after the class" ? like this?:confused:

class MyElement
{

...
};
Q_REGISTER_METATYPE(MyElement*);
qRegisterMetaType<MyElement*>("MyElement*");

Kumosan
3rd September 2007, 13:15
My advice might not help for your concrete problem, but you really should ponder a bit whether you can redesign you code that you don't need to signal pointers. Technically nothing is wrong with that, but it might require a higher effort to keep ownership matters in check. For my taste it simply smells not 'robust' enough. :)

Shawn
3rd September 2007, 13:23
My advice might not help for your concrete problem, but you really should ponder a bit whether you can redesign you code that you don't need to signal pointers. Technically nothing is wrong with that, but it might require a higher effort to keep ownership matters in check. For my taste it simply smells not 'robust' enough. :)


Thanks very much for this advice.

Actually what bothers me most is how to "design" code. Obviously I am lack of this very "taste" now. I am not a professional programmer...

What I tried to implement is to show a hirachy tree structure in a treeWidget. If I click any item in this treeWidget, it's additional information can be shown in a tableWidget.
My idea is subclass treeWidgetItem and make the data structrue to be memeber of this MyTreeWidgetItem. And so, I may have to singal object-pointers to see which item has been clicked.

Is there any advice for this? I think my situation is commom...

marcel
3rd September 2007, 13:31
Q_REGISTER_METATTYPE goes in the header and qRegisterMetaType in the source.


What I tried to implement is to show a hirachy tree structure in a treeWidget. If I click any item in this treeWidget, it's additional information can be shown in a tableWidget.
My idea is subclass treeWidgetItem and make the data structrue to be memeber of this MyTreeWidgetItem. And so, I may have to singal object-pointers to see which item has been clicked.

You could emit only the index but having the object is always better.
As for the ownership, you could solve that by making the class where you create the elements the parent and have it destroy them as they aren't needed anymore. Or even in the destructor.

Regards

Shawn
3rd September 2007, 15:44
This is my first thought,
note: MyView* w; Element* pE;

item is clicked ---> emit MyRectItem::a_signal ---> MyRectItem::a_slot ---> call w->showTree(pE)

then I wander this one may be better,
item is clicked ---> emit MyRectItem::b_signal(pE) ---> MyView::shot: showTree(pE)

Actually which one is better ?
How should I design my code ?

marcel
3rd September 2007, 16:30
The second is better. This is closer to the purpose of signals and slots -- transparently calling functions across different objects.

Your first solution does not make much sense :) - you connect a signal to a slot in the same object and then call some function in the view. You might have as well called the function in the view in the first place.

So, go with the second one.

Regards

Shawn
3rd September 2007, 17:28
OK, 1:16am now but I have finish it the second way:D

The next problem is:
How can I know which item in QTreeWidget has been clicked? Since I have subclassed QTreeWidgetItem to MyTreeWidgetItem, which contains an Element* . How can I emit a signal like itemSelected(Element*) ?

When I subclass the QGraphicsrectItem I implement it like this

class MyRectItem : public QObject, public QGraphicsRectItem
{
Q_OBJECT
public:
...
Element* pE;
signals:
void itemisSelected(bool newState);
void itemSelected(Element* pE);
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == QGraphicsItem::ItemSelectedChange)
{
bool newState = value.toBool();
if (newState == true)
{
emit itemisSelected(newState);
}
}
return QGraphicsItem::itemChange(change, value);
}
};

And I connected the signal itemis Selected(bool) with signal itemSelected(Element*) right after I new a MyRectItem. It works well.

Is there any similar way to emit a signal(Element*) in MyTreeWidgetItem?