Поддержка множественного добавления / удаления (и отмены / повтора) с помощью QAbstractItemModel (C ++)

Привет,

Я писал неприятный код для поддержки отмены / возврата удаления произвольного набора объектов из моей модели. Мне кажется, что я делаю это правильно, поскольку все другие мутаторы (добавление / копирование-вставка) являются подмножествами этой функции.

Код более мерзкий, чем мне нужно, в основном потому, что единственный способ изменить модель включает вызов beginInsertRows / beginRemoveRows и удаление строк в диапазоне (просто выполняя по одной строке за раз, нет необходимости оптимизировать "соседей" в одну звоните пока)

Проблема с beginInsertRows / beginRemoveRows заключается в том, что удаление строки может повлиять на другой QModelIndex (скажем, кэшированный в списке). Например:

ParentObj
   ->ChildObj1
   ->ChildObj2
   ->ChildObj3

Скажем, я выбираю ChildObj1 и ChildObj3 и удаляю их, если я сначала удалю ChildObj1, я изменил QModelIndex ChildObj3 (строка теперь другая). Подобные проблемы возникают, если я удаляю родительский объект (но я исправил это, «вырезав» дочерние элементы из списка объектов).

Вот способы, которыми я думал обойти это ограничение интерфейса, но я подумал, что попрошу лучше, прежде чем двигаться дальше:

  1. Двигайтесь «назад», предполагая, что предоставленный список QModelIndices упорядочен сверху вниз, просто двигайтесь снизу вверх. Это действительно требует, чтобы сортировка была надежной, и сортировка, вероятно, была бы чем-то наивным и медленным (может быть, есть умный способ сортировки коллекции QModelIndexes? Или QItemSelectionModel предоставляет хорошие (упорядоченные) списки?)

  2. Обновляйте другие QModelIndeces каждый раз, когда объект удаляется / добавляется (не могу придумать ненаивное решение, выполните поиск в списке, получите новые QModelIndeces там, где это необходимо)

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

Это идеи, которые у меня есть сейчас. Я сейчас работаю над вариантом 1.

С уважением, Дэн О


person Dan O    schedule 12.11.2009    source источник


Ответы (2)


Думайте о beginRemoveRows / endRemoveRows и т. Д. Как о методах, которые просят базовый класс QAbstractItemModel исправить для вас постоянные индексы модели, а не просто способ обновления представлений, и постарайтесь не запутать базовый класс QAbstractItemModel в его работе с этими индексами. Ознакомьтесь с http://labs.trolltech.com/page/Projects/Itemview/Modeltest, чтобы проверить вашу модель и убедиться, что вы поддерживаете базовый класс QAbstractItemModel.

QPersistentModelIndex не помогает, если вы хотите сохранить данные отмены / повтора вне модели. Я построил модель, которая сильно отредактирована, и я не хотел пытаться сохранить все в модели. Я храню данные отмены / повтора в стеке отмены. Проблема в том, что если вы редактируете столбец, сохраняя постоянный индекс этого столбца в стеке отмены, а затем удаляете строку, содержащую этот столбец, постоянный индекс столбца становится недействительным.

Что я делаю, так это сохраняю как постоянный модельный индекс, так и «исторический» регулярный QModelIndex. Когда пришло время отменить / повторить, я проверяю, не стал ли постоянный индекс недействительным. Если это так, я передаю исторический QModelIndex специальному методу моей модели, чтобы попросить его воссоздать индекс на основе строки, столбца и internalPointer. Поскольку все мои правки находятся в стеке отмены, к тому времени, когда я сделаю резервную копию этого редактирования столбца в стеке отмены, строка обязательно будет там в модели. Я сохраняю достаточно состояния во internalPointer, чтобы воссоздать исходный индекс.

person Jim Flood    schedule 18.12.2009
comment
Является ли использование QPersistantModelIndex единственным разумным способом? Классы Qt MVC кажутся мне действительно устаревшими ... - person Georg Schölly; 01.01.2010
comment
Для отмены использование чего-то вроде полного пути к элементу - единственный разумный способ xway. В своих новых документах Nokia прямо заявляет об этом и предупреждает, что QPersistentModelIndex недостаточно хорош. В случае Джима это работает, но потому что он хранит достаточно состояния во internalPointer QModelIndex. Если internalPointer - это просто указатель, например, на узел дерева, который может быть удален, используйте пути. Это просто; просто список пар (строка, столбец). - person Paul Du Bois; 03.02.2011

Я бы подумал об использовании модели «все данные» и прокси-модели фильтра с моделью данных. Данные будут только добавляться в модель всех данных и никогда не удаляться. Таким образом, вы можете хранить информацию об отмене / повторении со ссылками на эту модель. (Могу я предложить QPersistentModelIndex?). Ваша модель данных также может каким-то образом отслеживать то, что должно быть показано. Тогда модель фильтра будет возвращать информацию только для тех элементов, которые должны отображаться в данный момент.

person Caleb Huitt - cjhuitt    schedule 12.11.2009
comment
Я не разработчик приложений (это просто хобби-проект), но никогда не освобождать объекты в моей модели - это зло. Эффективное индексирование такого (в конечном итоге) большого и глубоко вложенного набора данных также кажется маловероятным. QPersistentModelIndex кажется очень интересным, я постараюсь использовать этот класс. - person Dan O; 12.11.2009
comment
@Dan O: вам нужно будет где-то хранить данные, либо в вашем дереве отмены / повтора, либо в другом месте, например, в модели данных. Я должен уточнить, что другая модель не должна удалять данные никогда, а только в определенные, четко определенные моменты времени (которые затем могут взаимодействовать с вашим кодом отмены / повтора). - person Caleb Huitt - cjhuitt; 13.11.2009
comment
Да, я сохраняю данные в своих командах отмены / повтора. Управление временем жизни команд сейчас довольно чистое, поскольку они освобождаются стеком команд Undo / Redo. - person Dan O; 13.11.2009
comment
Я согласен с Дэном. По идее, стек отмены может хранить данные. Требуется механизм для хранения действительно постоянных индексов элементов, но это несложно. - person Paul Du Bois; 03.02.2011