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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: QTreeView + QAbstractItemModel после сортировки сбиваются индексы  (Прочитано 11546 раз)
Polt
Гость
« : Май 26, 2011, 23:01 »

Доброй ночи. qt 4.4.2. postgres 8.

На форме живет QTreeView, используется пользовательская модель QAbstractItemModel, в которой живет дерево, произростающее из rootItem. В дереве одна колонка. Дерево строится по данным из БД, но в данном случае это не важно. Соответственно данные организованы древовидно. Интерфейс должен позволять пользователю вести дерево, добавлять, удалять итемы и т.д. По умолчанию итемы дерева отсортированы.

RItem * rootItem       - указатель на корневой итем
QList<RItem *> childs - список указателей (детки каждого итема)

Функция добавления нового итема в дерево реализована через beginInsertRows() и endInsertRows(). Итем добавляется в конец childs выбранного родителя, потом срабатывает функция сортировки. После сортировки итемы сбиваются, причем QModelIndex после сортировки распологаются верно, но такое чувство что QTreeView не понял что произошла сортировка ветки с новым итемом в модели. При клике на итемы QTreeView после сортировки, выводя наименования итемов в консоль, становится понятно что итемы сбиты. Проблема решается после открытия и закрытия битой ветки, когда модель сама переиндексирует ветку. Так же проблема решается через reset() всей модели. Но после reset() приходится разворачивать все ветки дерева, выделять нужный итем (который был добавлен), а это лишнее время.

Если открывать и закрыть ветку программно после сортитровки, то теряется выделение правильного итема после добавления нового итема через beginInsertRows. Приходится выделять нужный итем, используя доп функцию. Теряется скорость, а это критично. Подскажите, как решить проблему без всякой черезжопности.
Записан
twp
Гость
« Ответ #1 : Май 27, 2011, 12:32 »

перед сортировкой лучше сделать beginResetModel() а после нее endResetModel() и сконнектить сигнал QAbstractItemModel::modelReset() со слотом QTreeView::expandAll()
Записан
Polt
Гость
« Ответ #2 : Май 27, 2011, 12:52 »

Вы предлагаете использовать begin/endResetModel. Это резетнет модель, что затратно по времени и на экране будет видно перерисовку, мерцание. Сконектить сигнал с expandAll... ммм это откроет/закроет все узлы, это тоже долго. Вы предлагаете при каждом добавлении нового итема в дерево резетить модель и закрывать/открывать все узлы. Это не подходит.

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

Вопрос остается. Но все равно спасибо за совет. Интересует как решить проблему не теряя выделение нового итема после добавления.

Где знатоки qt)
Записан
twp
Гость
« Ответ #3 : Май 27, 2011, 13:16 »

мерцания по идее не должно быть видно, ведь в этом случае перерисовка вью блокируется через setUpdatesEnabled(false). Если не подходит раскрытие всех узлов, то придется делать вручную, запоминать открытые узлы, а также выделенный индекс и восстанавливать после сортировки. Но в вашем случае лучше вообще не сортировать, а сразу определить правильное место для новой строки. Зачем все пересортировывать?
Записан
Polt
Гость
« Ответ #4 : Май 27, 2011, 13:27 »

Потому что реализован drag/drop и добавляться может несколько итемов сразу. Используется qSort(). Childs() это QList и удобно сортировать используя итератор.
Я с вами согласен, если самому вставлять итемы в нужные места, то данный вопрос решится, но зачем, неужели нельзя нормально подружить модель с представлением в данном случае?
Записан
Polt
Гость
« Ответ #5 : Май 27, 2011, 13:33 »

Кстати функция expandAll() у представления работает медленно. Если руками написать функцию, которая будет открывать только узлы (итемы у которых есть детки), можно неплохо выиграть времени.
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #6 : Май 27, 2011, 13:48 »

Цитировать
Итем добавляется в конец childs выбранного родителя, потом срабатывает функция сортировки.
Цитировать
Используется qSort().
Так как именно делается сортировка?
Записан

Qt 5.11/4.8.7 (X11/Win)
Polt
Гость
« Ответ #7 : Май 27, 2011, 13:58 »

Итем (кратко):

class RItem;
{
   RItem * parent;            - родитель
   QList<RItem *> childs;  - дети
}

Добавление итема Childs << newItem;
Сортировка          qSort(childs.begin; childs.end, функтор);
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #8 : Май 27, 2011, 14:06 »

Цитировать
Сортировка          qSort(childs.begin; childs.end, функтор);
Мде...
И как MVC узнает, что вы отсортировали детей элемента Непонимающий
Используйте QStandardItemModel и делайте сортировку через QStandardItem::sortChildren().
Записан

Qt 5.11/4.8.7 (X11/Win)
Polt
Гость
« Ответ #9 : Май 27, 2011, 14:23 »

В том-то и дело, что никак.

sortChildren() мммм... Мне необходима сортировка итемов по типу. А не по алфавиту.
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #10 : Май 27, 2011, 14:31 »

Использовать
Код
C++ (Qt)
void QStandardItemModel::setSortRole( int role )
либо перегружать
Код
C++ (Qt)
bool QStandardItem::operator< ( const QStandardItem & other ) const [virtual]
либо вообще навесить на уже используемую модель QSortFilterProxyModel и перегрузить
Код
C++ (Qt)
bool QSortFilterProxyModel::lessThan ( const QModelIndex & left, const QModelIndex & right ) const [virtual protected]
либо перейти на QTreeWidget, где всё это уже есть )
« Последнее редактирование: Май 27, 2011, 14:45 от GreatSnake » Записан

Qt 5.11/4.8.7 (X11/Win)
Polt
Гость
« Ответ #11 : Май 27, 2011, 15:20 »

QTreeWidget медленный.
Переход на QStandardItemModel возможен, но долгий, потому что написано уже много.
А вот использование QSortFilterProxyModel интересно.

Спасибо за советы.
Записан
Polt
Гость
« Ответ #12 : Май 27, 2011, 16:33 »

Построил дерево через QStandardItemModel пока что без сортировки веток по типу.
Моя модель строилась намного шустрее. Так что оставлю свой вариант.
Если время найду, попробую привинтить QSortFilterProxyModel к своей модели.

Вопрос не решен. Но людям, которым скорость работы не критична, вариант с QStandardItemModel подойдет.
Записан
twp
Гость
« Ответ #13 : Май 27, 2011, 16:36 »

если QTreeWidget медленный, то после навешивания прокси модели скорее будет еще медленней. Все таки я придерживаюсь мнения что нужно изначально вставить строки в нужные позиции. В данном случае можно поступить так:
1. Берем копию чайлдов и добавляем новые строки
2. Сортируем
3. Пробегаемся по этой копии и ищем вставленные строки, тем самым находя строку (индекс в списке) для вставки.
4. Вставляем уже в настоящий список чайлдов через beginInsertRows/endInsertRows новые строки
Записан
Polt
Гость
« Ответ #14 : Май 27, 2011, 16:41 »

Ну если ничего не поможет, то придется добавлять итемы в нужные позиции и не сортировать ветку.
Потом сравню с сортировкой qSort + открытие/закрытие ветки + выделение нужного итема.
Замерю тайминги и обязательно напишу тут что шустрее.

Спасибо за предложения.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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