PDA

View Full Version : Problem emiting signal in QTreeWidgetItem's subclass



Shawn
3rd September 2007, 18:32
Since this is totally new question which has nothing to do with the title of my provious post, I post it here.

I have subclassed QTreeWidgetItem to MyTreeWidgetItem, which contains an Element* .
Then how can I know which item in QTreeWidget has been clicked?
Can I emit a signal like itemSelected(Element*) ?

I used to subclass the QGraphicsrectItem and emit a signal contains this Element* 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);
}
};
I connected the signal itemisSelected(bool) with signal itemSelected(Element*) right after I new a MyRectItem. And it works well.

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

jpn
3rd September 2007, 19:37
Does MyTreeWidgetItem inherit QObject? What did you try so far?

Shawn
4th September 2007, 01:22
Does MyTreeWidgetItem inherit QObject? What did you try so far?

Yes, it inherits QObject

class MyTreeWidgetItem : public QObject, public QTreeWidgetItem
{
Q_OBJECT

public:
MyTreeWidgetItem(QTreeWidget* parent);
MyTreeWidgetItem(MyTreeWidgetItem* parent);
~MyTreeWidgetItem();

Element* pE;
signals:
void itemClicked(MyTreeWidgetItem* item, int column);

private slots:
void slot_itemSelected();
};
int Q_REGISTER_METATYPE(MyTreeWidgetItem*);

In QGraphicsItem, the enum QGraphicsItem::GraphicsItemChange are sent as the state changes, and I can catch this and emit a signal, which "carrys" the Element* .

But in QTreeWidgetItem I can not find anything like GraphicsItemChange.

I tried to used the signal void itemClicked(QTreeWidgetItem* item, int column) in QTreeWidget, but it can only "return" QTreeWidgetItem*...

marcel
4th September 2007, 04:51
You can find that by reimplementing QTreeWidget's mouse press event. In this function you should verify what QTreeWidget::itemAt(QMouseEvent:: pos()) returns. If it is not null means that you clicked on an item and you can emit that. Otherwise you clicked somewhere in the view, not on an item and you can act accordingly.

Regards

Shawn
4th September 2007, 06:16
You can find that by reimplementing QTreeWidget's mouse press event. In this function you should verify what QTreeWidget::itemAt(QMouseEvent:: pos()) returns. If it is not null means that you clicked on an item and you can emit that. Otherwise you clicked somewhere in the view, not on an item and you can act accordingly.

Regards

Maybe this is a stupid question.
How can I reimplement QTreeWidget's mouse press event? Should I subclass the QTreeWidget and reimplement the event there ? OR I can reimplement this mose event in MyTreeWidgetItem ?

marcel
4th September 2007, 06:54
No, you have to subclass QTreeWidget. Remember that mousePressEvent is virtual protected.

jpn
4th September 2007, 06:58
Perhaps you could even use the built-in signal QTreeWidget::itemClicked(QTreeWidget* item, int column) and simply cast the passed item:


connect(treeWidget, SIGNAL(itemClicked(QTreeWidget*, int)), receiver, SLOT(doSomething(QTreeWidget*, int)));

void Receiver::doSomething(QTreeWidget* item, int column)
{
MyTreeWidgetItem* myItem = dynamic_cast<MyTreeWidgetItem*>(item);
if (myItem)
{
// yes, it's a "MyTreeWidgetItem", do something with it's "element"
}
}

Actually you could store the element information as QTreeWidgetItem's user data, without the need of subclassing QTreeWidgetItem.

Shawn
4th September 2007, 08:07
Perhaps you could even use the built-in signal QTreeWidget::itemClicked(QTreeWidget* item, int column) and simply cast the passed item:


connect(treeWidget, SIGNAL(itemClicked(QTreeWidget*, int)), receiver, SLOT(doSomething(QTreeWidget*, int)));

void Receiver::doSomething(QTreeWidget* item, int column)
{
MyTreeWidgetItem* myItem = dynamic_cast<MyTreeWidgetItem*>(item);
if (myItem)
{
// yes, it's a "MyTreeWidgetItem", do something with it's "element"
}
}

Actually you could store the element information as QTreeWidgetItem's user data, without the need of subclassing QTreeWidgetItem.

I did what you said,

QObject::connect(ui.treeWidget, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(testslot(QTreeWidgetItem*, int)));
void test::testslot(QTreeWidgetItem* item, int column)
{
QString str = item->text(column);
QMessageBox::information(0, "testslot", str, QMessageBox::Ok);
}
The strange thing is that the message box appears many times when I click on any item. 22 times on my laptop and 38 or 39 times on my workstation...:confused:

Shawn
4th September 2007, 08:45
The strange thing is that the message box appears many times when I click on any item. 22 times on my laptop and 38 or 39 times on my workstation...:confused:

I test it using a local static variable, and found that the exact times the testslot has been called is 22. Why it behaves like this ?

jpn
4th September 2007, 09:21
Do you call QObject::connect() in a loop?

Shawn
4th September 2007, 09:43
Sorry, stupid mistake:(

I connected in a recursion function...

After replace it to the constractor, it works well:D:p

Thanks very much for your help!

Shawn
4th September 2007, 12:03
Perhaps you could even use the built-in signal QTreeWidget::itemClicked(QTreeWidget* item, int column) and simply cast the passed item:


connect(treeWidget, SIGNAL(itemClicked(QTreeWidget*, int)), receiver, SLOT(doSomething(QTreeWidget*, int)));

void Receiver::doSomething(QTreeWidget* item, int column)
{
MyTreeWidgetItem* myItem = dynamic_cast<MyTreeWidgetItem*>(item);
if (myItem)
{
// yes, it's a "MyTreeWidgetItem", do something with it's "element"
}
}

Actually you could store the element information as QTreeWidgetItem's user data, without the need of subclassing QTreeWidgetItem.

The program works now, but I still doesn't understand your code. Especially for the dynamic_cast function, how can it get the "element" information only by MyTreeWidgetItem's parent class ?

If you have time, can you explain it a little bit? If you can recommend some metarial that I can study this by myself, I will appreciate it as well.

marcel
4th September 2007, 12:08
Go to this address and download Thinking in C++( Bruce Eckel) and read the chapter on polymorphism: http://www.mindview.net/Books/DownloadSites.

Regards