Cleaning QLayout (Part One)

One time I was interested in a way to clean up QLayout, since I had a task to make sure some items are reloaded at some point of software execution. Then, I came up across SO page: http://stackoverflow.com/questions/4857188/clearing-a-layout-in-qt . There were various suggestions of clearing a layout in Qt. I was using one of them for a reasonable period of time. However, this proved to be a huge mistake. And I will show you why.

In the series of these posts, I am going to take a look into existing suggestions to clear QLayout. Then, I will take a look into each suggestion, and will show the problem behind each of them. Finally, I will provide you completely proper way to clear QLayout. I would even encourage you to use this solution in your production-level code, since it is completely tested, verified and proved to be stable for a long period of time.

In this post, I am going to take a look into existing suggestions to clear QLayout. There are a couple of them. The first one is an “official solution” to this problem, i.e. described in Qt documentation itself. According to http://doc.qt.io/qt-5/qlayout.html:

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;
}

Basically, the solution is just to delete QLayoutItem, and everything would look fine. However, this solution is wrong, since it does not remove widgets from a layout. So, from this solution we can assume Qt treats differently removing items, widgets, and other objects. Well, in our case clearing layout means completely deleting everything that can be treated as layout level item (in another part, I will take a look into more rigorous definition).

Another solution to clear layout is the one I came across on SO: http://stackoverflow.com/a/4857631/1027730. According to this solution, the following code fragment is good enough to clear QLayout:

void clearLayout(QLayout *layout)
    QLayoutItem *item;
    while((item = layout->takeAt(0))) {
        if (item->layout()) {
            clearLayout(item->layout());
            delete item->layout();
        }
        if (item->widget()) {
            delete item->widget();
        }
        delete item;
    }
}

I must confess that I was using this variation of code myself. This solution is good enough, since it also takes into account the possible fact that layout might have not just widgets, layout items, but widgets in it, then widget in it might have some layouts of it, and so on. So, this code basically makes sure that layout becomes completely empty. However, the biggest problem with this solution is delete item->widget(); code line. Why? Because widgets can send signals, and it is possible that deleting happens when widget’s signals are handled while not being returned from the event loop. And when such a thing happens, we might experience application crash.

In summary, we have these two solutions. And the last solution looks to be taking into account all the clearing logic. However, it is still not complete enough, since it does not take into account event loop being in place (which takes central role in Qt as framework in itself).

Leave a Reply

Your email address will not be published. Required fields are marked *