Russian Qt Forum
Ноябрь 22, 2024, 22:40 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Удаление итемов в TreeModel  (Прочитано 2893 раз)
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, удалить их через контекстное меню, затем выбрать любой другой итем.




« Последнее редактирование: Февраль 19, 2015, 15:09 от ibnz » Записан
Swa
Самовар
**
Offline Offline

Сообщений: 170


Просмотр профиля
« Ответ #1 : Февраль 19, 2015, 16:54 »

Между beginRemoveRows и endRemoveRows вам нужно удалять объект из списка, в котором он находится. Вы просто очищаете память, занимаемую объектом, и оставляете его трупик в списке. Неудивительно, что падает.

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

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

Записан
ibnz
Гость
« Ответ #2 : Февраль 19, 2015, 16:56 »

Между beginRemoveRows и endRemoveRows вам нужно удалять объект из списка, в котором он находится. Вы просто очищаете память, занимаемую объектом, и оставляете его трупик в списке. Неудивительно, что падает.

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

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



все это происходит в деструкторе PointScenario
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.1 секунд. Запросов: 22.