PDA

View Full Version : Remove widget from a QList



Eos Pengwern
13th October 2009, 00:34
Hello; I wonder if anyone can help with this...

In my GUI I have a fairly complicated matrix of widgets in a QGridLayout. From time to time, I need to add or remove rows of widgets from the GUI.

I store pointers to each widget in a set of QLists, one for each type of widget. Adding widgets is no problem. I simply use:


// First, remove from the layout all the widgets in rows below the one to be inserted
...
// Then, add a new widget in row 'i'
MyWidgetList.insert(i, new MyCustomWidget(i));
// Then, repopulate the layout from row 'i' downwards
...

where MyWidgetList is a QList<MyCustomWidget *>. In effect, there are three distinct operations here: firstly, create a new widget; secondly, insert its pointer into the QList; thirdly, add the new widget to the layout.

However, I get into trouble when trying to remove a widget. In principle, I'd like to be able to do the above in reverse. Taking the widget out of the layout is easy, but I'm getting tied in knots over how to both remove the pointer from the QList AND destroy the widget itself. Currently, I use:


// First, remove the widget from the layout:
MyLayout -> removeWidget(MyWidgetList.at(i));
// Now call the destructor:
MyWidgetList.at(i) -> ~MyCustomWidget();
// Now delete the pointer:
MyWidgetList.removeAt(i);
// Finally, refresh the layout once again...

When compiled with gcc, this seems to work, but then I seem to get random crashes after I've done this a couple of times, implying a memory leak. When compiled with MSVC, the program stops with an exception from deep within the heap management routines.

There must be a 'proper' way to do this. The QList documenation provides the following example for clearing out all the widgets from a QList, namely:


qDeleteAll(list.begin(), list.end());
list.clear();

...but there are no clues how one might go about clearing out a single entry.

Can anyone advise?

jano_alex_es
13th October 2009, 10:13
why are you calling the destructor? just delete it.


// Now call the destructor:
delete(MyWidgetList[i]);

Eos Pengwern
14th October 2009, 10:06
You're right; that works!

Classic beginner's error: getting so carried away with Qt's own methods that one overlooks the methods that standard C++ provides.

Thank you very much.

ComaWhite
14th October 2009, 13:00
You could also do this


delete MyWidgetList.takeAt(i);

Eos Pengwern
16th October 2009, 22:25
There's actually a postscript to this, which I'll record here for the benefit of anyone else who tries to do the same thing.

Even after replacing my destructors with delete(), I still got heap errors when running in debug mode (and periodic crashes when outside the debugger). So, I resorted to Qt Support, and learned the real problem was this: among the various widgets that were being deleted was the 'delete' button on that row, whose 'clicked' signal was connected to the slot function that carries out the deleting.

Now, Qt expects (quite reasonably) that when a signal is emitted and a slot function is called, it should be able to return afterwards to the object that emitted the signal. In this case, that object had been deleted by the end of the slot function, so there was nowhere for it to return to. Hence the heap error.

Fortunately, the solution was very simple: just the addition of the Qt::QueuedConnection qualifier to the applicable signal/slot connection, i.e. changing



connect(Delete_Buttons.at(i), SIGNAL(clicked(const int &)),
this, SLOT(removeFilm(const int &)));


...to:



connect(Delete_Buttons.at(i), SIGNAL(clicked(const int &)),
this, SLOT(removeFilm(const int &)), Qt::QueuedConnection);


That was the only change required, and now it works perfectly.