Russian Qt Forum

Qt => Model-View (MV) => Тема начата: ibnz от Февраль 19, 2015, 15:05



Название: Удаление итемов в TreeModel
Отправлено: ibnz от Февраль 19, 2015, 15:05
Пытаюсь разобраться в том как написать правильную иерархическую модель в рамках Qt MV фреймворка.
тестовый примерчик на битбакете:
https://bitbucket.org/ibnz/treemodeltest
Проблемы возникли с тем как правильно удалять итемы. А именно с тем, как отследить некорректные указатели в индексах после удаления.

Проблемная функция - удаление произвольного списка итемов.
Код:
void ModelScenarioPoint::removeList(const QModelIndexList &list)
{
    QList<QPersistentModelIndex> persistentList;
    foreach (const QModelIndex &i, list) persistentList << QPersistentModelIndex(i);
    foreach (const QPersistentModelIndex &i, persistentList) {
        PointScenario *p = getPoint(i);
        if (p == m_rootPoint) continue;
        beginRemoveRows(i.parent(), i.row(), i.row());{
            delete p;
        }endRemoveRows();
    }
}

Очевидно, что проблема будет при удалении парента раньше чайлдов, если таковые будут иметься в списке.
Но это не самое неприятное.
Даже если удалять итемы из одного уровня иерархии может получить падение сразу, либо в дальнейшем.
Проблема в строчке
Код:
beginRemoveRows(i.parent(), i.row(), i.row());
Очевидно, я ее использую не совсем так, как следует. Несмотря ни на что после endRemoveRows() я продолжаю получать индексы от SelectionModel с невалидными internalPointer().

Делать QSet<PointScenario *> с актуальными указателями на итемы, и проверять на вхождение при получении в getPoint, как то коряво и неэффективно.

В примере для падения достаточно выделить итемы 21 и 22, удалить их через контекстное меню, затем выбрать любой другой итем.






Название: Re: Удаление итемов в TreeModel
Отправлено: Swa от Февраль 19, 2015, 16:54
Между beginRemoveRows и endRemoveRows вам нужно удалять объект из списка, в котором он находится. Вы просто очищаете память, занимаемую объектом, и оставляете его трупик в списке. Неудивительно, что падает.

Должно быть так:

Код:
PointScenario* item = parent->childList[row];
beginRemoveRows(i, row, row);{
  parent->childList.removeOne(item);
  delete item;
}endRemoveRows();



Название: Re: Удаление итемов в TreeModel
Отправлено: ibnz от Февраль 19, 2015, 16:56
Между beginRemoveRows и endRemoveRows вам нужно удалять объект из списка, в котором он находится. Вы просто очищаете память, занимаемую объектом, и оставляете его трупик в списке. Неудивительно, что падает.

Должно быть так:

Код:
PointScenario* item = parent->childList[row];
beginRemoveRows(i, row, row);{
  parent->childList.removeOne(item);
  delete item;
}endRemoveRows();



все это происходит в деструкторе PointScenario