PDA

View Full Version : How to clear all elements in a QGraphicsScene? (qt 4.2)



Morea
8th September 2006, 16:19
How do you do that?
I get a lot of
QGraphicsScene::removeItem: item 0x81bc010's scene ((nil)) is different from this scene (0x80f6388)

when trying to



if (myscene != NULL)
{
QList<QGraphicsItem*> L = myscene->items();
while (!L.empty())
{
myscene->removeItem(L.first());
delete L.first();
}
}

jacek
8th September 2006, 16:35
Try:
qDeletaAll( myscene->items() );(you will have to add #include <QtAlgorithms>).

Morea
8th September 2006, 16:43
Great, thanks. Qt feels quite large...

What did I do wrong?

jacek
8th September 2006, 16:54
What did I do wrong?
"delete L.first()" deletes only the object that the first item in the list points to --- it doesn't remove the item.


while( ! L.empty() ) {
myscene->removeItem( L.first() ); // this line isn't necessary --- item destructor will handle this
delete L.first();
L.removeFirst(); // <- the missing line
}
qDeleteAll() is a shorthand for the above loop (without the removeItem() call).

hb
14th September 2007, 13:37
while( ! L.empty() ) {
myscene->removeItem( L.first() ); // this line isn't necessary --- item destructor will handle this
delete L.first();
L.removeFirst(); // <- the missing line
}
qDeleteAll() is a shorthand for the above loop (without the removeItem() call).

This code however will have problems if some of the QGraphicsItems are children of other QGraphicsItems. As the children will automatically be destroyed with their parents, you'll get double frees and program crashes.

I use the following code (which is a slot of my QGraphicsScene-derived class) to clear the scene:


void MyGraphicsScene::clear()
{
bool itemDeleted = true;
QList <QGraphicsItem*> itemList = items();

while (itemDeleted && !itemList.isEmpty()) {
int numItems = itemList.size();
int iItem;
itemDeleted = false;
for (iItem = 0; (iItem < numItems) && !itemDeleted; iItem++) {
QGraphicsItem *item = itemList.at(iItem);
if (item->parentItem() == NULL) {
removeItem(item);
delete item;
itemDeleted = true;
}
}
itemList = items();
}
if (!itemList.isEmpty() && !itemDeleted)
qWarning("Problem in MyGraphicsScene::clear()");
}


This doesn't look exactly pretty, but works for me.

hb
14th September 2007, 15:09
This code however will have problems if some of the QGraphicsItems are children of other QGraphicsItems. As the children will automatically be destroyed with their parents, you'll get double frees and program crashes.


Actually, thinking about it it's probably cleaner to first get a list of all top-level items, and then use the method jacek described to clear that list instead of the whole items() list.

Code to get a list of all top-level items could look like this:


QList<QGraphicsItem*> MyGraphicsScene::getTopLevelItems()
{
int numItems, iItem;
QList<QGraphicsItem*> topLevel;
QList<QGraphicsItem*> itemList = items();

numItems = itemList.size();
for (iItem = 0; iItem < numItems; iItem++) {
QGraphicsItem *item = itemList.at(iItem);
if (item->parentItem() == NULL)
topLevel.append(item);
}
return topLevel;
}

Bitto
16th September 2007, 10:48
Hm. QGraphicsScene::clear() would probably be nice.

Gopala Krishna
16th September 2007, 16:34
Hm. QGraphicsScene::clear() would probably be nice.

True, also with an option to delete the cleared elements would be nice :)

hb
20th September 2007, 12:30
Hm. QGraphicsScene::clear() would probably be nice.

I agree. And personally, I would find a QGraphicsScene::topLevelItems() also useful, since I have the impression that in most applications, interaction is mostly done with toplevel items only.

klnusbaum
11th August 2008, 19:46
It's not exactly the most efficient way of doing things, but this seems to work pretty well for me.


void SubClassedQGraphicsScene::clear(){
QList <QGraphicsItem*> itemList = items();
while(!itemList.isEmpty()){
delete itemList.first();
itemList = items();
}
}


I think trolltech needs to put a clear() function in the QGraphicsScene class though.

jpn
11th August 2008, 21:47
I think trolltech needs to put a clear() function in the QGraphicsScene class though.
They did already, QGraphicsScene::clear() was introduced in Qt 4.4.