I've written a derived class from QGraphicsScene. At a point I need to remove all items from the scene and I want the items to be physically destroyed (destructor called). I tried the following:
QList<QGraphicsItem*> all = items();
for (int i = 0; i < all.size(); i++)
{
QGraphicsItem *gi = all[i];
removeItem(gi);
delete gi; // warning at this line
}
Qt Creator emits a warning: warning: C4150: deletion of pointer to incomplete type 'QGraphicsItem'; no destructor called
I'm not sure why is that. QGraphicsItem has virtual destructor so the items should be deleted from memory.
If this is not the right way, how can I delete all QGraphicsItems from QGraphicsScene? Note that I know when the scene is deleted, all items will also be deleted. But i want to remove items from scene and draw other items. I want the removed items to be deleted from memory.
You can remove and delete all items with QGraphicsScene::clear().
Like jpalecek pointed out, you are missing the header file. You should accept his answer. I am just going to point out two potential issues:
First of all, you don't need to call QGraphicsScene::removeItem(). QGraphicsItem::~QGraphicsItem() does that for you.
Secondly. Be careful if you put any QGraphicsItem inside of others. That is, you have items that are children of other items. The destructor of QGraphicsItem automatically delete all its children. So when you loop through the items returned from QGraphicsScene, you may end up deleting a child item that has already been deleted by its parent. For example, say you have 2 items, A and B, and B is a child of A. When you delete A, B is deleted automatically. And then you get to B and try to delete it. BOOM!
A safer way to do this is to test if the item is the top level one, i.e. it has no parent:
QList<QGraphicsItem*> all = items();
for (int i = 0; i < all.size(); i++)
{
QGraphicsItem *gi = all[i];
if(gi->parentItem()==NULL) {
delete gi;
}
}
You have to
#include <QGraphicsItem>
in that file. Otherwise, the compiler doesn't know what QGraphicsItem is, that it has a virtual destructor, etc.
Related
My source code ↓
ui->tableWidget->setItem(0,7,new QTableWidgetItem(QString::number(3)));
ui->tableWidget->item(0,7)->setTextAlignment(Qt::AlignCenter);
My approach :
delete ui->tableWidget->item(0,7);
If this memory is free?
If not, let me know any other method.
The call to setItem(...) passes ownership of the QTableWidgetItem to the QTableWidget.
Although QTableWidgetItem is not a QObject, it does take care to inform the QTableWidget about its deletion (from qtablewidget.cpp, Qt 5.1.1):
QTableWidgetItem::~QTableWidgetItem()
{
if (QTableModel *model = (view ? qobject_cast<QTableModel*>(view->model()) : 0))
model->removeItem(this);
view = 0;
delete d;
}
takeItem() sets the view of the item to null, releasing the ownership to the caller.
Because of this, the above code in the item's destructor model->removeItem(this); will not be called.
This means that you need to manually delete the QTableWidgetItem.
But it doesn't matter if you call takeItem(...) or not before deleting the item.
See also Remove QListWidgetItem: QListWidget::takeItem(item) vs delete item.
I am using the constructor QWidget(QWidget *parent). This parent widget contains a lot of child widgets. I need to clear all the child widgets from the parent at runtime. How can I do this?
Previous answer is wrong!! You cannot use findChildren to delete a widget's children, because Qt4's findChildren recursively lists children. Therefore, you will delete children of children, which then may be deleted twice, potentially crashing your app.
More generally, in Qt, taking a list of QObject pointers and deleting them one by one is dangerous, as destroying an object may chain-destroy other objects, due to the parent ownership mechanism, or by connecting a destroyed() signal to a deleteLater() slot. Therefore, destroying the first objects in the list may invalidate the next ones.
You need to list children widgets either by:
Passing the Qt::FindDirectChildrenOnly flag to findChild if you are using Qt5 (which did not exist when the question was asked...)
Using QLayout functions for listing items,
Using QObject::children, and for each test if it is a widget using isWidgetType() or a cast
Using findChild() in a loop and delete the result until it returns a null pointer
To take care of the recursivity problem pointed out by #galinette you can just remove the widgets in a while loop
while ( QWidget* w = findChild<QWidget*>() )
delete w;
Summarizing and supplementing:
For Qt5 in one line:
qDeleteAll(parentWidget->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));
For Qt5 for a lot of children, using setUpdatesEnabled():
parentWidget->setUpdatesEnabled(false);
qDeleteAll(parentWidget->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));
parentWidget->setUpdatesEnabled(true);
Note that this is not exception safe! While Qt does not at this time appear to throw exceptions here, the signal destroyed() could be connected to code that does throw, or an overridden Object::childEvent(QChildEvent*) could throw.
Better would be to use a helper class:
class UpdatesEnabledHelper
{
QWidget* m_parentWidget;
public:
UpdatesEnabledHelper(QWidget* parentWidget) : m_parentWidget(parentWidget) { parentWidget->setUpdatesEnabled(false); }
~UpdatesEnabledHelper() { m_parentWidget->setUpdatesEnabled(true); }
};
...
UpdatesEnabledHelper helper(parentWidget);
qDeleteAll(parentWidget->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));
For Qt4:
QList<QWidget*> childWidgets = parentWidget->findChildren<QWidget*>();
foreach(QWidget* widget, childWidgets)
if (widget->parentWidget() == parentWidget)
delete widget;
Removing from the QLayout works in both Qt4 and Qt5:
QLayoutItem* child;
while (NULL != (child = layout->takeAt(0))) // or nullptr instead of NULL
delete child;
QObjects (and therefore QWidgets) remove themselves (automagically) from their parent in their (QObject) destructor.
From Qt docs
The following code fragment shows a safe way to remove all items from a layout:
QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0) {
...
delete child;
}
You can use the following in your parent widget class:
QList<QWidget *> widgets = findChildren<QWidget *>();
foreach(QWidget * widget, widgets)
{
delete widget;
}
I know there is many questions about memory management in Qt. Also I read these SO questions:
Memory Management in Qt
Memory management in Qt?
Qt memory management. What's wrong?
But in my case, I confused again!
I have a QTableWidget with name myTable. I add run-time widgets to it by setCellWidget:
void MyClass::build()
{
for (int i=LOW; i<HIGH; i++)
{
QWidget *widget = new QWidget(myTable);
//
// ...
//
myTable->setCellWidget(i, 0, widget);
}
}
Then, I delete all items like below:
void MyClass::destroy()
{
for (int i = myTable->rowCount(); i >= 0; --i)
myTable->removeRow(i);
}
These methods call many times during long time. And myTable as the parent of those widgets will live along program's life-time.
Dose method destroy() release memory quite and automatically? Or I have to delete allocated widgets myself like below?
void MyClass::destroy2() // This maybe causes to crash !!
{
for (int i = myTable->rowCount(); i >= 0; --i)
{
QWidget *w = myTable->cellWidget(i, 0);
delete w;
myTable->removeRow(i);
}
}
Generally speaking, when in doubt or confused about how to use a class, consult the documentation that should've came with it. Fortunately, QTableWidget::setCellWidget() does in fact come with documentation:
void QTableWidget::setCellWidget ( int row, int column, QWidget * widget )
Sets the given widget to be displayed in the cell in the
given row and column, passing the ownership of the widget to the
table [emphasis mine]. If cell widget A is replaced with cell widget B, cell widget
A will be deleted. For example, in the code snippet below, the
QLineEdit object will be deleted.
setCellWidget(index, new QLineEdit);
...
setCellWidget(index, new QTextEdit);
After the call to myTable->setCellWidget(), the table now owns the widget you passed into it. That means that myTable is responsible for deleting the widgets you pass to setCellWidget(). You don't need to do delete w; when you're removing rows. Your first destroy() function should be sufficient.
From the documentation:
void QTableWidget::setCellWidget ( int row, int column, QWidget * widget )
Sets the given widget to be displayed in the cell in the given row and column, passing the ownership of the widget to the table.
If cell widget A is replaced with cell widget B, cell widget A will be deleted. For example, in the code snippet below, the QLineEdit object will be deleted.
That is, you don't clean up manually, as freeing of resources happens automatically down the Qt object tree, of which your widget has become a part.
In Qt, can I embed child widgets in their parent via composition, or do I have to create them with new?
class MyWindow : public QMainWindow
{
...
private:
QPushButton myButton;
}
MyWindow::MyWindow ()
: mybutton("Do Something", this)
{
...
}
The documentation says that any object derived from QObject will automatically destroyed when its parent is destroyed; this implies a call to delete, whcih in the above example would crash.
Do I have to use the following?
QPushButton* myButton;
myButton = new QPushButton("Do Something", this);
EDIT
The answers are quite diverse, and basically boil down to three possibilities:
Yes, composition is ok. Qt can figure out how the object was allocated and only delete heap-allocated objects (How does this work?)
Yes, composition is ok, but don't specify a parent, since the parent would otherwise call delete on the object (But won't a parent-less widget turn into a top-level window?)
No, widgets always have to be heap-allocated.
Which one is correct?
The non-static, non-heap member variables are deleted when that particular object's delete sequence starts. Only when all members are deleted, will it go to the destructor of the base class. Hence QPushButton myButton member will be deleted before ~QMainWindow() is called. And from QObject documentation: "If we delete a child object before its parent, Qt will automatically remove that object from the parent's list of children". Hence no crash will occur.
Object trees & ownership answers your question. Basically when the child object is created on the heap it will be deleted by its parent.
On the other hand when the child object is created on the stack the order of destruction is important. The child will be destroyed before its parent and will remove itself from its parent's list so that its destructor is not called twice.
There is also an example in that link that shows problematic order of destruction.
The documentation says that any object derived from QObject will automatically destroyed when its parent is destroyed; this implies a call to delete
No. It implies a call to the destructor of that particular entity.
Say in your example, if MyWindow is destroyed, it means the destructor of the MyWindow has been called. Which in turn will call the destructor myButton which is implemented already in QPushButton.
If you have composite entity, just the destructor will be called on that entity but not delete and so it won't crash.
Parent child relationships in Qt doesn't require specifically to be in a stack or heap. It can be in anything.
A similar example in parent child relationship over a stack is over here.
HTH..
The object will be destroyed only when it has a parent pointer, so you can use:
MyWindow::MyWindow ()
: mybutton("Do Something", 0)
{
...
}
You should create it on heap, since QObject will destroy it :
class MyWindow : public QMainWindow
{
...
private:
QPushButton *myButton;
}
MyWindow::MyWindow ()
: mybutton( new QPushButton( "Do Something", this) )
{
...
}
calling delete operator will not crash ur application, you can read the following quote
Qt's parent–child mechanism is implemented in QObject. When we create an object (a widget, validator, or any other kind) with a parent, the parent adds the object to the list of its children. When the parent is deleted, it walks through its list of children and deletes each child. The children themselves then delete all of their children, and so on recursively until none remain. The parent–child mechanism greatly simplifies memory management, reducing the risk of memory leaks. The only objects we must call delete on are the objects we create with new and that have no parent. And if we delete a child object before its parent, Qt will automatically remove that object from the parent's list of children.
note that the parent argument is NULL by default (default argument)
this is QPushButton Constructor
QPushButton ( const QString & text, QWidget * parent = 0 )
so u can use
MyWindow::MyWindow () : mybutton( new QPushButton( "Do Something") ){ ... }
and u can call delete on any component and any time
Qt will take care for this point
Let me just quote the source here.
816 QObject::~QObject()
817 {
818 Q_D(QObject);
819 d->wasDeleted = true;
820 d->blockSig = 0; // unblock signals so we always emit destroyed()
821
...
924
925 if (!d->children.isEmpty())
926 d->deleteChildren();
927
928 qt_removeObject(this);
929
930 if (d->parent) // remove it from parent object
931 d->setParent_helper(0);
932
933 #ifdef QT_JAMBI_BUILD
934 if (d->inEventHandler) {
935 qWarning("QObject: Do not delete object, '%s', during its event handler!",
936 objectName().isNull() ? "unnamed" : qPrintable(objectName()));
937 }
938 #endif
939 }
...
1897 void QObjectPrivate::deleteChildren()
1898 {
1899 const bool reallyWasDeleted = wasDeleted;
1900 wasDeleted = true;
1901 // delete children objects
1902 // don't use qDeleteAll as the destructor of the child might
1903 // delete siblings
1904 for (int i = 0; i < children.count(); ++i) {
1905 currentChildBeingDeleted = children.at(i);
1906 children[i] = 0;
1907 delete currentChildBeingDeleted;
1908 }
1909 children.clear();
1910 currentChildBeingDeleted = 0;
1911 wasDeleted = reallyWasDeleted;
1912 }
So as you can see, QObject does indeed delete each of its children in the destructor. In addition, the destructor is executed before destructors of any members; so if the composite in question equals the parent – then member QObject won't have any chance to remove itself from the children list of its parent.
This, unfortunately, means that you cannot compose a QObject into its parent. But you can compose into other objects, as well as allocate on stack – as soon as you guarantee to destruct the object or reset its parent to 0 before the parent starts destructing.
I recently started investigating Qt for myself and have the following question:
Suppose I have some QTreeWidget* widget. At some moment I want to add some items to it and this is done via the following call:
QList<QTreeWidgetItem*> items;
// Prepare the items
QTreeWidgetItem* item1 = new QTreeWidgetItem(...);
QTreeWidgetItem* item2 = new QTreeWidgetItem(...);
items.append(item1);
items.append(item2);
widget->addTopLevelItems(items);
So far it looks ok, but I don't actually understand who should control the objects' lifetime. I should explain this with an example:
Let's say, another function calls widget->clear();. I don't know what happens beneath this call but I do think that memory allocated for item1 and item2 doesn't get disposed here, because their ownage wasn't actually transfered. And, bang, we have a memory leak.
The question is the following - does Qt have something to offer for this kind of situation? I could use boost::shared_ptr or any other smart pointer and write something like
shared_ptr<QTreeWidgetItem> ptr(new QTreeWidgetItem(...));
items.append(ptr.get());
but I don't know if the Qt itself would try to make explicit delete calls on my pointers (which would be disastrous since I state them as shared_ptr-managed).
How would you solve this problem? Maybe everything is evident and I miss something really simple?
A quick peek into qtreewidget.cpp shows this:
void QTreeWidget::clear()
{
Q_D(QTreeWidget);
selectionModel()->clear();
d->treeModel()->clear();
}
void QTreeModel::clear()
{
SkipSorting skipSorting(this);
for (int i = 0; i < rootItem->childCount(); ++i) {
QTreeWidgetItem *item = rootItem->children.at(i);
item->par = 0;
item->view = 0;
delete item; // <<----- Aha!
}
rootItem->children.clear();
sortPendingTimer.stop();
reset();
}
So it would appear that your call to widget->addTopLevelItems() does indeed cause the QTreeWidget to take ownership of the QTreeWidgetItems. So you shouldn't delete them yourself, or hold them in a shared_ptr, or you'll end up with a double-delete problem.
Qt has its own smart pointers, take a look at http://doc.qt.io/archives/4.6/qsharedpointer.html . Normally, it is though advisable to use the standard ownership hierarchy of Qt whenever possible. That concept is described here:
http://doc.qt.io/archives/4.6/objecttrees.html
For your concrete example, this means that you should pass a pointer to the container (i.e. the QTreeWidget) to the constructor of the child objects. Every QWidget subclass constructor takes a pointer to a QWidget for that purpose. When you pass your child pointer to the container, the container takes over the responsibility to clean up the children. This is how you need to modify your example:
QTreeWidgetItem* item1 = new QTreeWidgetItem(..., widget);
QTreeWidgetItem* item2 = new QTreeWidgetItem(..., widget);
(I don't know what the ... are in your example, but the important thing for Qt memory management is the last argument).
Your example of using a smart pointer
shared_ptr<QTreeWidgetItem> ptr(new QTreeWidgetItem(...));
items.append(ptr.get());
is not a good idea, because you break the golden rule of smart pointers: Never use the raw pointer of a smart pointer managed object directly.
Many Qt class instances can be constructed with a parent QObject*. This parent controls the life time of the constructed child. See if QTreeWidgetItem can be linked to a parent widget, which seems so, reading Qt docs:
Items are usually constructed with a
parent that is either a QTreeWidget
(for top-level items) or a
QTreeWidgetItem (for items on lower
levels of the tree).