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)
Related
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.
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.
(I use Qt 4.7, Windows 7, 64bit).
I created a custom table. Each row is a horizontal layout with widgets.
The rows are kept in a QList for easy access, and the children too. The rows are also added inside the parent widget.
If I resize the parent widget, I calculate the new sizes, delete everything, and recreate it again.
My problem is that I don't want to delete any widget. Only when I clear the table, I do it.
Since I have the widgets inside a QList and inside the parent layouts, How can I remove all widgets in each row, delete all layouts, and then add those to new layouts?
If I do: takeAt(0) for every element inside each layout I have a QLayoutItem with a widget inside... How can I delete the layoutItem without deleting the widget?.... How do I remove the widget without killing it, no matter if it's in the parent or the child? Because there are many methods for deleting: removeItem, removeWidget... in a layout, but not takeWidget... just takeAt() and it gives a Qlayoutitem.
I tried several ways, but I still see the widgets no matter what happened to them.
Questions about this:
When does a widget get deleted? If I takeWidget(index) from a layout, is it deleted some time by itself? does it happen if I have a pointer to it in another list?
removeAt(index) does execute the delete method of a widget?
Ok. I got it working.
Let me explain how this Removing, keeping widgets works.
A widget is known by its parent layout. And you remove it through the layout. By doing:
layout()->removeAt(widget);
delete widget;
If you use takeAt(index) in a QLayout (or its children), it gives you a QLayoutItem. To access the widget inside, just use widget(). But there's no way to remove the widget without deleting it. So this approach is non valid.
In the Docs it tells a way to delete the elements:
QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0) {
...
delete child;
}
A special thing to note in Qt is the following:
If you have a hierarchy tree of layouts, added with addLayout() inside layouts, no matter how deep your widget is inserted, you can remove it from the child layouts or any of the parent layouts, if the tree path from the layout and this item is built from child layouts.
The easiest thing is to keep a list of pointers to all the items, in a custom table. When clearing the table to reconstruct it, just do this inside your widget:
CustomTableItem* item;
while ( !items_.isEmpty() && ( (item = items_.takeFirst()) != 0 ) ){
layout()->removeWidget(item);
delete item; // It works no matter where the item is
}
items_.clear(); // clear the list afterwards.
And it works perfectly, updates the layout too by itself.
If you want to keep the elements, just skip the "delete item;" and use them afterwards.
An important thing to note is that different "remove" functions work differently (as i understand on Qt Docs) in QList or similar widgets, and in a QLayout.
In the QList, removeAt actually removes the object.
(Qt 4.7 QList Docs)"Removes the item at index position i. i must be a valid index position in the list (i.e., 0 <= i < size())."
In a QLayout, removeWidget or removeItem don't remove the item/widget, you have the responsability to delete it, as I did before.
(Qt 4.7 QLayout Docs) "Removes the widget widget from the layout. After this call, it is the
caller's responsibility to give the widget a reasonable geometry or to
put the widget back into a layout."
Hope it helps. If you see any error, you could tell me and I will edit the answer!
More on deleting here:
Other stackoverflow post
A widget in Qt is a regular C++ object and can be deleted with the C++ delete operator as any other object:
delete myWidget;
In Qt there is always a parent-child relation between widgets. When the parent widget is destroyed, it will delete all its children. Usually, you do not need to think about explicitly deleting any widgets but the top level widgets, i.e., windows and dialogs. Qt will take care of deleting any child widgets.
QList::removeAt(int) does not delete the object that is removed, it only removes the object from the list. If you also want to delete the object you would have to do something like:
delete myList.takeAt(0);
This applies to all functions such as removeAt(int), takeAt(int), takeFirst(), etc. They never delete objects, they only remove them from the container (list, layout, scrollarea, etc). In most cases the ownership of the widget is then transferred to the caller, (the caller becomes responsible for deleting the widget as the parent-child relation breaks), but do not assume this is always the case, always read the documentation of the function.
I have a QTabWidget, and I defined showEvent for one of the child widget.
Now how can I know where the showEvent is from?
It could be:
Switched from other tabs
The current index of tabwidget was not changed, the whole window just become visible
Is that possible?
QShowEvent is very generic, so there's no direct way to get information about what triggered it. Depending on your needs either save current value of QTabWidget::currentIndex between show events or move your logic to QTabWidget::currentChanged slot.
i created one QWidget(Parent). in the inside of the parent widget i created another one QWidget(Child). In the run time i need to remove the child widget. how to do that?
i am not using any layout. i am directly putting in the Parent Widget.
Please Help me to fix this.
If you add the widget with e.g.:
QWidget *w = new QWidget(parent);
...then you can remove it with:
delete w;
Another approach would be to just hide it:
w->hide();
This answer is for those arriving from search engines and want an answer to the question as stated in the title.
If you want to remove a child from a parent without deleting it or hiding it (which does NOT remove it from its parent), set the child's parent to NULL.
QWidget::setParent(NULL)
Note that explicitly reparenting a widget like this carries several implications (e.g visibility automatically set to hidden). See QWidgets documentation for more information.