3

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?

SexyBeast
  • 7,913
  • 28
  • 108
  • 196
  • Possible duplicate of [About deleting, removing widgets and layouts in Qt 4](https://stackoverflow.com/questions/17703513/about-deleting-removing-widgets-and-layouts-in-qt-4) – Supamee Aug 04 '17 at 16:13

2 Answers2

4

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.

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • May be QListView will work, but I need to make it work with QLayout currently. Any pointer? – SexyBeast Feb 04 '15 at 17:08
  • @Cupidvogel So the clear answer is that you must use `removeWidget` and then you or whatever previous owner the widget had will clean it up. Then you'll need to call `update` and whatever other adjustments are required to get the layout to look right again. Let me just beg you one more time, "Don't do this, please, for your sake, for anyone else who has to look at the codebase's sake, and for my sake as someone who just hates making things wrong." – Jonathan Mee Feb 04 '15 at 18:38
  • 1
    Ok then, it would be cruel to not pay heed to your sincere request.. :) Gonna use QListView. Let me see how I can make that work.. – SexyBeast Feb 04 '15 at 18:50
  • @Cupidvogel You should know that I feel happier and like the world is a better place! Qt's `QListView` is their simplest `QAbstractItemView`, but you still will need to dip into the `SelectionModel` and the `QAbstractItemModel` at times. This is a paradigm that you will use over and over in Qt, so don't think that you are wasting your time as you learn. [This example](http://doc.qt.io/qt-5/qtwidgets-itemviews-puzzle-example.html) will probably be particularly useful to you as you get started. If you have questions along the way post a link to them here and I'll come try to answer. – Jonathan Mee Feb 04 '15 at 19:00
  • How do I clear a QListView? And by the way, should I be using a QListView or QListWidget? – SexyBeast Feb 05 '15 at 07:42
  • @Cupidvogel 1) [Qt says](http://doc.qt.io/qt-5/qlistwidget.html#details): `QListWidget` is a convenience class that provides a list view similar to the one supplied by `QListView`, but with a classic item-based interface for adding and removing items. `QListWidget` uses an internal model to manage each `QListWidgetItem` in the list. For a more flexible list view widget, use the `QListView` class with a standard model. 2) Clearing a `QListView` requires getting the `QAbstractItemModel` and calling [`removeColumn`](http://doc.qt.io/qt-5/qabstractitemmodel.html#removeColumn) – Jonathan Mee Feb 05 '15 at 12:32
0

Actually you can solve this issue easily, even if you are using QGridLayout or any other Layouts :

    subLayout->removeWidget(m_visibleCheckBox);//removes and then it causes some zigzag drawing at (0,0)

    m_visibleCheckBox->setVisible(false);//asks to redraw the component internally

    setLayout(subLayout);//for safety as we may use that layout again and again

If you just use the first line it will cause this :

qt removeWidget best way

Maifee Ul Asad
  • 3,992
  • 6
  • 38
  • 86