[Qt-interest] deleteLater() for QGraphicsItem

Daniel Price daniel.price at fxhome.com
Thu Dec 3 10:19:39 CET 2009


We hit the same problem but there is a really simply solution - when you remove the item from the scene, wrap the pointer to in a QObject-derived class which calls deleteLater() in the constructor. Create this object on the heap with new() but ignore the return pointer. In the destructor, delete the graphics item. Here's my templated version that can be used with any type:

#include <QObject>

template <typename T>
class DelayedDelete : public QObject
{
public:
                explicit DelayedDelete(T *&item) : m_item(item)
                {
                                item = 0;
                                deleteLater();
                }
                virtual ~DelayedDelete()
                {
                                delete m_item;
                }
private:
                T *m_item;
};

You'll notice that the constructor takes a reference to the original pointer which it sets to 0 after copying it in the initialize list - this avoid leaving a hanging pointer in the calling code which DelayedDelete has taken ownership of. Here's how it's called:

scene->removeItem(gfxItem);
new DelayedDelete<RectItem>(gfxItem); // would have crashed if gfxItem was deleted here

Where RectItem is my QGraphicsItem-derived class. As you can see it's fire-and-forget. Qt will delete the DelayedDelete instance during the next event loop. But as far as your code is concerned, gfxItem is dead.

You don't want to be casting stuff or deriving graphicsItems from QObject.

This does seem like a bug in Qt. But this solution has served us well (not just with graphicsItems). I can't take complete credit for it - the idea was KDAB's but I did write the template version :)

From: qt-interest-bounces at trolltech.com [mailto:qt-interest-bounces at trolltech.com] On Behalf Of Andreas Unger
Sent: 03 December 2009 06:28
To: qt-interest at trolltech.com
Subject: Re: [Qt-interest] deleteLater() for QGraphicsItem



I have a QGraphicsView with a bunch of objects that inherit from QGraphicsItem (QGraphicsRectItem or QGraphicsPixmapItem) and QObject, and QGraphicsProxyWidgets. For some reason, I can't delete the items directly without the application crashing -- I have to use deleteLater()

Since QGraphicsScene::clear() deletes all items which causes my application to crash, I'm trying to maintain a list of the items that have been added to the scene that will be removed and deleted later on. Since the items inherit from QObject, I can directly call deleteLater() on them. However, if I add them the items to a list, I have to cast them to a common type that they all inherit from such as QGraphicsItem or QObject.

Given that QGraphicsItem has no deleteLater() method, I cast these items to QObject* and in my customClear() method, I remove all the items in my list of items from the scene and call deleteLater() on them, then I call QGraphicsScene::clear(). If I dynamically cast every QObject* in the list to QGraphicsItem, I can remove the item from the scene, call deleteLater() on it. Then I can call QGraphicsScene::clear() since all items that could not be safely deleted using 'delete' as opposed to 'deleteLater()' have already been removed from the scene. That works fine, I think.

I think that dynamic casts cause a runtime overhead that I want to avoid. If I do a reinterpret_cast from QObject* to QGraphicsItem* (so that I can be able to call the QGraphicsScene::removeItem method), the address of the QGraphicsItem* is no longer the same and I can thus not remove the item, and an eventual QGraphicsSceneClear() causes a crash, since the original pointer hasn't been removed from the scene()->items() list.

I hope I've explained myself well. Can anyone suggest  to me a better way of doing what I'm trying to do?

I'd like to clarify that what I'd like to do is some kind of type introspection, meaning that I store a hash map of the QObject* and and int (or String) and when I want to remove the items from the scene and call deleteLater() on them, I iterate through the hash map, and for every key in the hash map, I get a value which tells me what derived class the object belongs to and I do a reinterpret_cast from a QObject* to MyItemClass*. Then I remove the item from the scene and call deleteLater() on it. The easiest way I can think of doing this is a bunch of ifs or a switch statement that checks the string (or int) to see what derived class the QObject belongs to, but I'm wondering whether there's a simpler Qt way of doing what I'm trying to do or some elegant method/design pattern...



No virus found in this incoming message.
Checked by AVG - www.avg.com
Version: 9.0.709 / Virus Database: 270.14.89/2539 - Release Date: 12/01/09 19:32:00

________________________________
This email is confidential. It may also be privileged or otherwise protected by work product immunity or other legal rules. If you are not the intended recipient please notify the sender. Please delete the message from all places in your computer where it is stored. You should not copy the email or use it for any purpose or disclose its contents to any other person.To do so may be unlawful. Email is an informal means of communicating and may be subject to data corruption accidentally or deliberately. For this reason it is inappropriate to rely on advice contained in an email without obtaining written confirmation of it first.

FXhome Limited is a limited company registered in England and Wales. Registered number: 04172812. Registered office: The Henderson Business Centre, Ivy Road, Norwich, Norfolk, NR5 8BF, U.K.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20091203/59c289e0/attachment.html 


More information about the Qt-interest-old mailing list