Как удалить виджеты из макета в Qt

У меня есть фрагмент кода, который делает это: метод с именем prepareUI делает пользовательский интерфейс готовым к загрузке результатов поиска, которые в него подаются. Метод с именем onClear, который вызывается, когда уже отображаемые результаты необходимо очистить. И метод с именем populateSearchResults, который берет данные поиска и загружает их в пользовательский интерфейс. Контейнер, в котором хранятся данные, является общедоступным указателем, поскольку он необходим для очистки результатов от 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);
}

Проблема в том, что когда я вызываю onClear, который внутренне вызывает delete, он удаляет все отображаемые результаты. Но после этого, если я снова вызову populateWithSearchesults, мое приложение выйдет из строя, и трассировка стека покажет, где этот метод дал сбой.

Как решить эту проблему?


person SexyBeast    schedule 04.02.2015    source источник


Ответы (2)


Похоже, у вас есть некоторые неверные представления о собственности. QLayout становится владельцем любого добавляемого к нему элемента: http://doc.qt.io/qt-5/qlayout.html#addItem

Это означает, что QLayout отвечает за удаление этих элементов. Если вы удалите их, QLayout также попытается удалить их, и тогда вы получите сбой, который вы видите сейчас.

QLayout не имеет хорошей функциональности для удаления содержимого и его повторного добавления (например, removeWidget возможно, не работает так, как вы надеетесь.) Но для этого есть причина.

QLayout не предназначен для использования в качестве списка.

Чего вы действительно хотите, так это, подождите, QListView. Который будет даже обрабатывать функции прокрутки для вас, и добавлять и удалять элементы.

person Jonathan Mee    schedule 04.02.2015
comment
Возможно, QListView будет работать, но сейчас мне нужно, чтобы он работал с QLayout. Любой указатель? - person SexyBeast; 04.02.2015
comment
@Cupidvogel Итак, четкий ответ заключается в том, что вы должны использовать removeWidget, а затем вы или любой другой предыдущий владелец виджета очистите его. Затем вам нужно будет вызвать update и выполнить любые другие корректировки, необходимые для того, чтобы макет снова выглядел правильно. Позвольте мне еще раз попросить вас: не делайте этого, пожалуйста, ради себя, ради всех, кому приходится смотреть на кодовую базу, и ради меня, как человека, который просто ненавидит делать что-то не так. - person Jonathan Mee; 04.02.2015
comment
Хорошо, тогда было бы жестоко не прислушаться к вашей искренней просьбе.. :) Собираюсь использовать QListView. Позвольте мне посмотреть, как я могу заставить это работать. - person SexyBeast; 04.02.2015
comment
@Cupidvogel Вы должны знать, что я чувствую себя счастливее и что мир стал лучше! QListView в Qt — это самый простой QAbstractItemView, но вам все равно придется время от времени окунуться в SelectionModel и QAbstractItemModel. Это парадигма, которую вы будете использовать снова и снова в Qt, так что не думайте, что вы тратите свое время на обучение. Этот пример, вероятно, будет вам особенно полезен, поскольку вы начинаете. Если у вас возникнут вопросы по пути, разместите ссылку на них здесь, и я приду, чтобы попытаться ответить. - person Jonathan Mee; 04.02.2015
comment
Большое спасибо! Сделаю.. :) - person SexyBeast; 04.02.2015
comment
Как очистить QListView? И кстати, должен ли я использовать QListView или QListWidget? - person SexyBeast; 05.02.2015
comment
@Cupidvogel 1) Qt говорит: QListWidget — это удобный класс, который предоставляет представление списка, аналогичное представленному QListView, но с классическим интерфейсом на основе элементов для добавления и удаления элементов. QListWidget использует внутреннюю модель для управления каждым QListWidgetItem в списке. Для более гибкого виджета представления списка используйте класс QListView со стандартной моделью. 2) Для очистки QListView требуется получить QAbstractItemModel и вызвать removeColumn. - person Jonathan Mee; 05.02.2015

На самом деле вы можете легко решить эту проблему, даже если вы используете QGridLayout или любые другие Layout:

    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

Если вы просто используете первую строку, это вызовет следующее:

qt removeWidget лучший способ

person Maifee Ul Asad    schedule 09.12.2020