Search code examples
c++qtpointersqlayout

How to remove widgets from layout in Qt


I have a piece of code which does this: a method named prepareUI makes the UI ready to be able to load search results that are fed into it. A method named onClear that is called when the results that are already showing needs to be cleared. And a method named populateSearchResults that takes the search data and loads the UI with it. The container that holds the data is a publicly available pointer, since it is needed to clear the results from onClear:

void MyClass::prepareSearchUI() {
        //there may be many search results, hence need a scroll view to hold them
        fResultsViewBox = new QScrollArea(this);
        fResultsViewBox->setGeometry(28,169,224,232);
        fSearchResultsLayout = new QGridLayout();
}

void MyClass::onClear() {
    //I have tried this, this causes the problem, even though it clears the data correctly
    delete fSearchResultContainer;
    //tried this, does nothing
    QLayoutItem *child;
    while ((child = fSearchResultsLayout->takeAt(0)) != 0)  {
        ...
        delete child;
    }
}

void MyClass::populateWithSearchesults(std::vector<std::string> &aSearchItems) {
    fSearchResultContainer = new QWidget();
    fSearchResultContainer->setLayout(fSearchResultsLayout);

    for (int rowNum = 0; rowNum < aSearchItems.size(); rowNum++) {
        QHBoxLayout *row = new QHBoxLayout();
        //populate the row with some widgets, all allocated through 'new', without specifying any parent, like
        QPushButton *loc = new QPushButton("Foo");
        row->addWidget(loc);
        fSearchResultsLayout->addLayout(row, rowNum, 0,1,2);    
    }
    fResultsViewBox->setWidget(fSearchResultContainer);
}

Problem is, when I call onClear which internally calls delete, it does remove all the results that were showing. But after that, if I call populateWithSearchesults again, my app crashes, and the stack trace shows this method as where it crashed.

How do I fix this problem?


Solution

  • It seems that you have some misconceptions about ownership. A QLayout takes ownership of any item that is added to it: http://doc.qt.io/qt-5/qlayout.html#addItem

    That means the QLayout is responsible for deleting these items. If you delete them then the QLayout will also try to delete them and then you get the crash you're seeing now.

    QLayout doesn't have good functionality for deleting contents and re-adding them (for example removeWidget probably doesn't work as you would hope.) But there's a reason for this.

    QLayout is not intended to be used as a list view.

    What you do want is a, wait for it, QListView. Which will even handle the scroll functionality for you, and make adding and removing elements a possibility.