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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: QAbstractItemModel + QTreeView + обновление в модели по ключу id + key [РЕШЕНО]  (Прочитано 8001 раз)
vintik
Гость
« : Февраль 16, 2012, 19:29 »

Всем привет!
Проблема следующая. Есть куча данных. Их удобно представлять в виде дерева. Есть модель для дерева. Данные отображаются в QTreeView
Данные отображаемые в дереве - это некие ключи.
x
|------y1
|        |-----1
|        |-----2
|------y2
|        |-----1
|        |-----2

Есть внешний источник, который шлёт сигналы например следующего типа. Ключ номер <y2, 2> больше не живой - его нужно удалить (т.е нужно удалить подузел 2 в узле y2) .
Стандартная реализация модели предполагает при манипуляции с моделью использовать индексы
(  bool QAbstractItemModel::removeRows ( int row, int count, const QModelIndex & parent = QModelIndex())   ).
Вопрос в том, как правильно и грамотно установить соответствие между приходящим ключом и индексом?
Первая мысль была такая: при создании нового узла в дереве (модели) - индекс (QModelIndex) сохранять в хеш используя ключ (тот самый <y2, 2>).
А потом когда нужно удалить узел - получать индекс из хеша по ключу. И по индексу удалять.

Но обнаружилась проблема - после удаления чего-либо из модели внутренняя индексация изменяется.
Т.е. если раньше по индексу createIndex(3, 0, root) были доступны одни данные, то после
removeRows(2, 0, QModelIndex())
по индексу createIndex(3, 0, root) - уже другие данные.
И получается, что я ожидаю что по ключу <y2, 2> получу индекс для удаления именно этого узла из дерева - а на деле получаю индекс для удаления уже другого узла.

Думаю - есть какие-то иные стандартизированные способы для решения проблемы, подскажите куда копать?
« Последнее редактирование: Март 03, 2012, 10:01 от vintik » Записан
vintik
Гость
« Ответ #1 : Февраль 24, 2012, 09:37 »

значит вот что получилось - два способа:
1. Вообще забить на хранение соответствия между приходящим ключом и индексом. Воспользоваться методом QAbstractItemModel::match для поиска индекса листа в котором хранится y2, а потом для уже для найденного индекса тем же методом искать индекс листа, в котором хранится 2. По полученному индексу осуществлять удаление.
+ ничего не надо нигде хранить
- если обращение к модели частое (мой случай), то на поиск конкретного листа уходит много времени.

2. Использовать QTreeWidget вместо QTreeView и самописной модели. В QTreeWidget лист представляет из себя объект класса QTreeWidgetItem. Указатель на этот объект можно сохранить в хеше по ключу (<y2, 2>). Удалять лист уже не по индексу, а по сохранённому указателю.
Плюсы и минусы диаметрально противоположны первому случаю.

Оба подхода достаточно поверхностны, так что если кто-то обладает опытом в решении подобных проблем, буду рад совету
Записан
Bepec
Гость
« Ответ #2 : Февраль 24, 2012, 09:43 »

А что тебе мешает вообще представить это деревом в виде списка?
Тогда помоему будет вообще не проблема.
Записан
vintik
Гость
« Ответ #3 : Февраль 24, 2012, 10:26 »

Если честно ничего не мешает)
Дерево красивше смотрится.

Если я правильно понял, то 1ый список - листья 1го уровня, 2ой список - листья 2го уровня. И так далее, сколько уровней вложений, столько и списков?

      list1              |   list2
y1 <-- current      |   1
y2                      |   2

И ещё вопрос, если я буду использовать свою модель для списка, то удаление из модели тоже только через индексы? Я правильно понимаю? Если да, то снова встаёт проблема - как удалять что либо из модели по ключу?
« Последнее редактирование: Февраль 24, 2012, 10:37 от vintik » Записан
andrew.k
Гость
« Ответ #4 : Февраль 24, 2012, 10:41 »

Но обнаружилась проблема - после удаления чего-либо из модели внутренняя индексация изменяется.
Т.е. если раньше по индексу createIndex(3, 0, root) были доступны одни данные, то после
removeRows(2, 0, QModelIndex())
по индексу createIndex(3, 0, root) - уже другие данные.
И получается, что я ожидаю что по ключу <y2, 2> получу индекс для удаления именно этого узла из дерева - а на деле получаю индекс для удаления уже другого узла.
Ну так ты обновляй не только модель, но и хеш, где у тебя хранятся индексы. Только ту ветку, которая была затронута удалением.
Тогда удаление будет чуть подольше, а поиск быстрее.
Записан
vintik
Гость
« Ответ #5 : Февраль 24, 2012, 11:29 »

Смотри, я правильно рассуждаю?

Индекс определяется 3мя параметрами (номер строки, номер колонки, родитель)
Приходит сигнал, в нём ключ, по ключу я определяю, что например индекс (3, 0, root) нужно удалить. Удаляю.
Потом мне нужно найти все элементы хэша, у которых в значении лежат индексы из диапазона [ (4, 0, root); (rowCount(root) - 1, 0, root) ] - номер строки нужно уменьшить на 1.

hash.insert(hash.key(createIndex(4, 0, root)), createIndex(3, 0, root))
hash.insert(hash.key(createIndex(5, 0, root)), createIndex(4, 0, root))
...
hash.insert(hash.key(createIndex(rowCount(root) - 1, 0, root)), createIndex(rowCount(root) - 1 - 1, 0, root))

« Последнее редактирование: Февраль 24, 2012, 14:14 от vintik » Записан
andrew.k
Гость
« Ответ #6 : Февраль 24, 2012, 14:11 »

что у тебя ключ в хеше? и что является твоим ключом?
я думал, что ключ в хеше это какой-то ид из бд, а значение это индекс модели.тебе надо обновить в хеше индексы всех новых, а один лишний наверное можно и не удалять.
Записан
vintik
Гость
« Ответ #7 : Февраль 24, 2012, 14:22 »

да, ключ в хэше. ключ представляет из себя пару чисел типа int. Он приходит в виде сигнала от стороннего модуля. По нему я получаю данные и строю элементы дерева. Ну т.е. пришёл ключ <1,4> эт значит что у корня появляется лист 1 и у листа 1 появляется лист 4. А со временем приходит сигнал для этого же ключа, о том что его нужно удалить из дерева.

попробовал вариант выше предложенный - да работает, но катастрофически долго!!! hash.key()  ужасно долго отрабатывает
Записан
andrew.k
Гость
« Ответ #8 : Февраль 24, 2012, 16:32 »

да, ключ в хэше. ключ представляет из себя пару чисел типа int. Он приходит в виде сигнала от стороннего модуля. По нему я получаю данные и строю элементы дерева. Ну т.е. пришёл ключ <1,4> эт значит что у корня появляется лист 1 и у листа 1 появляется лист 4. А
Т.е. все листья имеют уникальный индекс?
Записан
vintik
Гость
« Ответ #9 : Февраль 26, 2012, 10:00 »

Т.е. все листья имеют уникальный индекс?
да, именно так
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Февраль 26, 2012, 14:02 »

Эта проблема (индексы "уплывают" при вставке/удалении) возникает и без всякого model-view. Мне неизвестен какой-то общий метод. В дополнение к сказанному выше (если все же хочется работать по индексу)

- если удаление сосредоточено в одном месте, то удаляющий имеет ввиду смещение индексов

- то же но чуть в профиль: отложить удаление и (пока) маркировать doomed элемент (часто занося его в доп контейнер).  Затем в какой-то момент удалить физически и переиндексироваться
Записан
Tonal
Гость
« Ответ #11 : Февраль 27, 2012, 11:36 »

Вроде всё решается вполне просто:
После удаления узла выносишь из хеша его и его детей и обновляешь в индексы его братьев снизу. Улыбающийся

Я использую beginRemoveRows endRemoveRows + несколько внутренних кешей для ускорения.
Записан
vintik
Гость
« Ответ #12 : Февраль 27, 2012, 16:38 »

Вроде всё решается вполне просто:
После удаления узла выносишь из хеша его и его детей и обновляешь в индексы его братьев снизу. Улыбающийся

Я использую beginRemoveRows endRemoveRows + несколько внутренних кешей для ускорения.

Суть ясна, но вот немного бы пояснения про внутренние кешы для ускорения, может пример какой-нить есть))
Записан
vintik
Гость
« Ответ #13 : Март 03, 2012, 10:00 »

Чтобы как-то завершить тему, скажу, что остановился на 2ом варианте из второго поста
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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