Why is it more efficient to remove a QGraphicsItem from its scene before destroying it? - qt

According to the QGraphicsItem destructor documentation, "It is more efficient to remove the item from the QGraphicsScene before destroying the item."
Why is that? I can't think of how it could make a difference. And if it did make a difference, shouldn't the QGraphicsItem destructor just call:
if (scene() != NULL)
scene()->removeItem(this);
I checked the source, and this does not seem to be the case, although sometimes I have a tough time understanding Qt source. EDIT: See comments in jdi's answer.

Maybe I am interpreting the docs differently than you (I have not looked at the source):
QGraphicsItem::~QGraphicsItem () [virtual]
Destroys the QGraphicsItem
and all its children. If this item is currently associated with a
scene, the item will be removed from the scene before it is deleted.
Note: It is more efficient to remove the item from the QGraphicsScene
before destroying the item.
I take that to mean it will remove it from the scene first before destroying because that is more efficient. But if you say the source does not indicate anywhere that this occurs, then is seems the docs would be false?
If I had to take a guess as to why it would be more efficient to remove the item first before destroying it (regardless of whether the API really does it for you in the destructor), I would think it would have to do with what triggers the scene to reindex. Maybe by deleting an item that is still in the scene, the cascading deletions of child items would constantly trigger the scene to reindex. Whereas, if you were to remove the item first, it may efficiently pull out the entire hierarchy in a way that only requires a single update of the scene, and then the normal deletion can occur without further affecting it? There may even be more cascading effects of other child events/signals while they are deleted within the scene.
I'm betting the logic behind the "Note" is to inform those who would subclass a QGraphicsItem and overload the destructor to keep in mind the need to remove from the scene first.

Related

Issue regarding setting parent of widget in Qt

From this post here, in general:
All QObjects will delete their own child objects automatically. (See
docs here.) QWidgets are QObjects. So as long as you establish a
parent/child relationship, you do not need to manually delete your
objects. To do that, simply pass a pointer to the parent object to the
constructor:
QLabel *label1 = new QLabel; // <<- NEED TO DELETE
QLabel *label2 = new QLabel(some_parent_obj); // Will be deleted when some_parent_obj is deleted
So some questions arises:
Does every widget necessary needed/required a parent? If no, what are the exceptions? If yes, what happens to widgets without parent?
I asked this because from examples in Qt Docs, some example widgets have parents (QLabel example) but some doesn't (QBarChart example, and also QFont, QColor, etc...).
So I'm wondering if there's an exception, or those widgets just don't need any parents, or if I declare them with new for some reason, I have to delete afterward.
And vice versa...
Does a widget without parent guarantee to cause a memory leak (or something similar) when the widget which it stays in (not necessary its parent) is deleted? Or if it's removed from a layout without any deletion happening?
Because from my experience with my code, I've created probably quite a lot (~100) of widgets and other stuffs without neither setting any parent (nor using delete afterward), and the project appears to run fine without any stalls even after a while (the effect might be underlying though, as I haven't run Memcheck), hence this question is here.
Does every widget necessary needed/required a parent?
If you want them to be deleted automatically - yes. But...
If no, what are the exceptions? If yes, what happens to widgets without parent?
You do not need to provide a parent to widget if you attach it to layout using QLayout::addWidget. If you look into source code, you'll see that when you do so, it automatically attaches layout's parent as widget's parent(unless you didn't attach layout to any widget).
But if you leave the widget created with new without parent and do not attach to anything - it is leaking memory. You must delete it either using delete or QObject::deleteLater. The last option is recommended when object has any connections.
Does a widget without parent guarantee to cause a memory leak (or something similar) when the widget which it stays in (not necessary its parent) is deleted? Or if it's removed from a layout without any deletion happening?
As I already mention QLayout::addWidget sets parent for added widget, so the answer is no. Also note, that when you call QLayout::removeWidget, it removes only QLayoutItem from layout, but widget's parent stays the same as it was after calling QLayout::addWidget.

Add a delete Button to each Item in QListView

Is it somehow possible to add to each Item in a QListview a Button which is deleting the Object onClick? As shown in the following Picture:
EDIT: As I'm new in QT it would be nice to have some example, to understand it better. And as it seems there are three different Ways? What will be the best? Do use a QAbstractItemView?
Yes. You'll need to use:
QAbstractItemView::setIndexWidget ( const QModelIndex & index, QWidget * widget )
QListView inherits QAbstractItemView and when you're trying to customize list/tree views that's usually the place to look. Be careful though, without a delegate this doesn't scale very well. Check out this thread: http://www.qtcentre.org/threads/26916-inserting-custom-Widget-to-listview
You can also go for a generic approach that can work on variety of containers, including the underlying model of your list view.
Each item in the list has a requestRemoval(Item*) signal and a removeMe() slot, connect the X button to the removeMe() slot in each item constructor, in removeMe() you emit the requestRemoval(this) signal, which is connected to a removeHandler(Item*) slot in your "parent" object upon creation of that item, which receives the pointer of the item which has requests deletion, and removes it from the underlying container being used.
Basically, pressing the remove button causes that particular item to send a pointer of itself to the parent's remove handler which removes that entry.
EDIT: Note that this is a generic approach, as noted in the comments below it can be applied without signals and slots as well, and even though it will work it is not the most efficient solution in your particular case.

Events and signals in Qt's QGraphicsItem: How is this *supposed* to work?

Like other primitives in Qt, QGraphicsItems can handle mouse events and the like. Sweet! Now say I need for an event on one QGraphicsItem to be propagated to some other QGraphicsItems in the same scene. I can think of two ways that one might approach this:
(A) The Naive Approach - Signaling
Concept : Connect sibling QGraphicsItems together with signals. Event handlers on QGraphicsItem call emit()s that evoke coordinated responses on other QGraphicItems. This follows the general design pattern established throughout the Qt framework.
Implementation : For reasons that I do not fully grasp, QGraphicsItems cannot emit() signals. It has been suggested that derived classes that also inherit from QGraphicsObject may be able to work around this. It seems to me, though, that the exclusion of emit() on QGraphicsItems was probably an intentional design decision on the part of the Qt devs and, therefore, multiple inheritance is probably not the Right Solution.
(B) Container-Level Event Handling
Concept : QGraphicsItems always exist in the context of a container of type QGraphicsScene. Events that in (A) were handled at the level of the QGraphicsItem are instead handled by an object inheriting from QGraphicsScene. This object also implements the logic for coordinating responses between sibling QGraphicsItems.
Implementation : QGraphicsScene definitely has the ability to handle events that would otherwise make their way down to QGraphicsItems. QGraphicsScene also provides the itemsAt() method for determining which of the things in it are affected by positional events, like mouse clicks. Still, building up considerable logic within a container class for coordinated action among containees feels like a failure to encapsulate properly. Bad practice? Maybe, but this seems to be the way it's done in at least one official example.
Questions
What's the Right Solution here? If not A or B, then is it something else that I haven't thought of?
Why did the Qt devs allow QGraphicsItems to receive events but not send signals? This seems like a major exception to the design pattern used throughout the framework.
An extension of this problem is communication between QGraphicsItems and higher-order container classes, like the main application. How is that meant to be addressed?
Signaling is not part of QGraphicItem because they do not inherit from QObjects. This was a design decision for performance reasons, to allow very large and fast scenes. If you decide you really need special cases for signals, QGraphicsWidget was created to fill this gap. It does inherit from QObject and lets you have a mixture of QWidget and QGraphicsItem functionality. Though it is recommended that you avoid this if your scenes are even moderately sizable.
Another option which might be relevant to your situation is to make use of the sceneEventFilter method. You can set one item to receive events for another and decide if they should be propagated or not:
http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qgraphicsitem.html#sceneEventFilter
One item can be set as the filter for multiple objects. And it can identify each individual item and event to respond to.
Generally though you should make use of the scene for coordination across its objects. That is already the pattern being used for events (the scene coordinating delivery of all events to the items).
Also, it seems that your option A is not possible because QGraphicsItem does not even have an emit method. You would need to compose a QObject instance inside it as a member and use that to emit signals. Something along the lines of myItem.qobject.emit(). Otherwise, you would have to inherit your own completely custom one from QGraphicsObject
Update 1: Addressing your main comment update
Your specific situation is a rectangle with "hot corners". I would see this being a custom QGraphicsItem. You would probably subclass QGraphicsRectItem, and then compose the child hot corner items inside as children items (setParentItem()). Now your rectangle item knows about its children and can act on them directly. You could set the rectangle item to be the sceneEventFilter for the children and handle their events directly. No need to go back up to the scene. Let all this logic live in the class.
Update 2: Addressing your added question #3
Propagating communications up beyond the scene to QWidget's has a couple approaches I can think of:
This is a situation where you can consider if you want to use a QGraphicsObject subclass as your root item, and then compose the rest of your objects as children (the rect, then the hot corners as children of the rect). This would allow the object to emit signals. For clarity they would probably still be connected to the scene, and then the higher order container of the scene would connect to the scene. You would have to choose this approach on a case by case, depending on the complexity of your scene and whether the QGraphicsObject has any performance impact on it. You should probably avoid this if you will have a great number of these instances.
You could define a callback for your rect class, for which the scene can set. Either something like: graphicsRect.resizedCallback as an attribute, or a setter graphicsRect.setResizedCallback(cbk). In your rect class, you would just call that when appropriate. If the callback it set, it can be used to call something on your scene directly. The rect class still has no knowledge of that logic. It just calls a callback.
Those are just some suggestions. I'm sure there are other ways.
I suggest B unless you have relatively few QGraphicsItems. I believe QGraphicsItems are not QObjects because there is a certain amount of overhead associated with QObjects. The QGraphicsView framework was designed to allow fast insertion and deletion of many (e.g., thousands) QGraphicsItems into a scene, so a lighter-weight approach was preferred.
I would look to the concept of parenting in QGraphicsItems. QGraphicsItems can have parents and children, and this has several effects similar to parenting amongst QObjects. For example, if you move a parent QGraphicsItem, its children will move with it, and if you delete a parent, its children will be deleted. You can access a QGraphicsItem's parent using QGraphicsItem::parentItem(), and children using QGraphicsItem::childItems(). So, you can easily access sibling items like this:
QList<QGraphicsItem *> mySiblings = this->parentItem()->childItems();
Note that mySiblings includes this.

Qt: Custom QListView and live controls

My custom QListView has delegates to paint the items. I'd like to add a live control to some of the row items (like a QLineEdit), that'll always be present in the row and will automatically scroll correctly with the list.
Since items are not widgets, I cannot assign a control to be a child of an "item", thus scrolling will leave the control in its fixed spot within the QListView widget.
Is there another way?
Is that even possible?
Normally the edit widget is created (and positioned) by the delegate when an QEvent::EnterEditFocus event occurs then destroyed when a subsequent QEvent::LeaveEditFocus occurs and the data is sent back to the model. The delegate should then repaint with the new model data.
Could you expand on what you mean by a "live" control?
Why would you want to have an edit widget constantly open? I think a better way to do this would be to create a delegate which paints the normal view (i.e. for Qt::DisplayRole) in a way which you want. Assuming you create your subclass view correctly, the delegate should still update when the model changes.
If you really want to do what you're asking though, I suspect you might be able to by:
creating your own item delegate (subclassing QAbstractItemDelegate)
reimplement createEditor() to use a QLineEdit
then use the delegate's updateEditorGeometry()
Have a read of the Delegate Classes section of the Introduction to Model/View Programming though first. The Spin Box Delegate Example and Pixelator Example are worth studying too if you haven't already.

How to remove QWidgets from QSplitter

In my app have a window splitted by a QSplitter, and I need to remove an widget.
How can I do that? I can't find useful methods
It's not clear to me if you want to preserve the widget and put it somewhere else, or if you want to destroy the widget.
Destroying the widget: If you can
get a pointer to the widget, you can
simply delete it. The splitter will
safely be notified that its child is
being deleted and will remove it
from itself.
Preserving the widget: If you grab
the pointer to the widget, you can
simply set its parent to some other
widget and add it to another
widget's layout and it will show up
there. This is safe because the
QSplitter will be notified that one
of its children is being reparented.
If you want to set the parent to NULL (cjhuitt's answer) be aware that you are now responsible for cleaning up that memory because the widget no longer has a parent.
Many things in Qt cannot be "traditionally" removed. Instead call hide() on it and destruct it. From QSplitter documentation:
When you hide() a child its space will
be distributed among the other
children. It will be reinstated when
you show() it again.
I like Tuminoid's answer. But if you absolutely need it removed, try getting the widget you want to remove, and calling setParent( NULL ) on that widget. That's my best guess.
If you hold a pointer to the widget, then just delete it, or use deleteLater() if you want to be on the safe side.
If you do not have the widget pointer, use QSplitter::widget(int index) function. Then, you can use invoke its deleteLater() slot.
If you do not have the widget index, but you still know the widget objectName(), then QObject::findChild() is your only way to get the widget pointer.
I ran into the same problem. In Qt 4.8 to temporally hide one of the widget of a QSplitter I simply hide it. However it is not enough, as the splitter handle is still available to move. But the handle can be accessed and hidden as well:
frameA->setVisible(conditionA);
frameB->setVisible(conditionB);
if ( !(conditionA && conditionB) ) // if only 1 frame is visible
{
splitter->handle(0)->setVisible(false);
}
Another easy way to prevent the child widget from getting deleted is to use QSplitter.takeWidget(child). This is also the recommended way of removing the widget from a splitter. (Qt Documentation)

Resources