Russian Qt Forum

Qt => Model-View (MV) => Тема начата: Polt от Май 26, 2011, 23:01



Название: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: 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. Приходится выделять нужный итем, используя доп функцию. Теряется скорость, а это критично. Подскажите, как решить проблему без всякой черезжопности.


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: twp от Май 27, 2011, 12:32
перед сортировкой лучше сделать beginResetModel() а после нее endResetModel() и сконнектить сигнал QAbstractItemModel::modelReset() со слотом QTreeView::expandAll()


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: Polt от Май 27, 2011, 12:52
Вы предлагаете использовать begin/endResetModel. Это резетнет модель, что затратно по времени и на экране будет видно перерисовку, мерцание. Сконектить сигнал с expandAll... ммм это откроет/закроет все узлы, это тоже долго. Вы предлагаете при каждом добавлении нового итема в дерево резетить модель и закрывать/открывать все узлы. Это не подходит.

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

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

Где знатоки qt)


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: twp от Май 27, 2011, 13:16
мерцания по идее не должно быть видно, ведь в этом случае перерисовка вью блокируется через setUpdatesEnabled(false). Если не подходит раскрытие всех узлов, то придется делать вручную, запоминать открытые узлы, а также выделенный индекс и восстанавливать после сортировки. Но в вашем случае лучше вообще не сортировать, а сразу определить правильное место для новой строки. Зачем все пересортировывать?


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: Polt от Май 27, 2011, 13:27
Потому что реализован drag/drop и добавляться может несколько итемов сразу. Используется qSort(). Childs() это QList и удобно сортировать используя итератор.
Я с вами согласен, если самому вставлять итемы в нужные места, то данный вопрос решится, но зачем, неужели нельзя нормально подружить модель с представлением в данном случае?


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: Polt от Май 27, 2011, 13:33
Кстати функция expandAll() у представления работает медленно. Если руками написать функцию, которая будет открывать только узлы (итемы у которых есть детки), можно неплохо выиграть времени.


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: GreatSnake от Май 27, 2011, 13:48
Цитировать
Итем добавляется в конец childs выбранного родителя, потом срабатывает функция сортировки.
Цитировать
Используется qSort().
Так как именно делается сортировка?


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: Polt от Май 27, 2011, 13:58
Итем (кратко):

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

Добавление итема Childs << newItem;
Сортировка          qSort(childs.begin; childs.end, функтор);


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: GreatSnake от Май 27, 2011, 14:06
Цитировать
Сортировка          qSort(childs.begin; childs.end, функтор);
Мде...
И как MVC узнает, что вы отсортировали детей элемента ???
Используйте QStandardItemModel и делайте сортировку через QStandardItem::sortChildren().


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: Polt от Май 27, 2011, 14:23
В том-то и дело, что никак.

sortChildren() мммм... Мне необходима сортировка итемов по типу. А не по алфавиту.


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: GreatSnake от Май 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, где всё это уже есть )


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: Polt от Май 27, 2011, 15:20
QTreeWidget медленный.
Переход на QStandardItemModel возможен, но долгий, потому что написано уже много.
А вот использование QSortFilterProxyModel интересно.

Спасибо за советы.


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: Polt от Май 27, 2011, 16:33
Построил дерево через QStandardItemModel пока что без сортировки веток по типу.
Моя модель строилась намного шустрее. Так что оставлю свой вариант.
Если время найду, попробую привинтить QSortFilterProxyModel к своей модели.

Вопрос не решен. Но людям, которым скорость работы не критична, вариант с QStandardItemModel подойдет.


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: twp от Май 27, 2011, 16:36
если QTreeWidget медленный, то после навешивания прокси модели скорее будет еще медленней. Все таки я придерживаюсь мнения что нужно изначально вставить строки в нужные позиции. В данном случае можно поступить так:
1. Берем копию чайлдов и добавляем новые строки
2. Сортируем
3. Пробегаемся по этой копии и ищем вставленные строки, тем самым находя строку (индекс в списке) для вставки.
4. Вставляем уже в настоящий список чайлдов через beginInsertRows/endInsertRows новые строки


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: Polt от Май 27, 2011, 16:41
Ну если ничего не поможет, то придется добавлять итемы в нужные позиции и не сортировать ветку.
Потом сравню с сортировкой qSort + открытие/закрытие ветки + выделение нужного итема.
Замерю тайминги и обязательно напишу тут что шустрее.

Спасибо за предложения.


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: Авварон от Май 28, 2011, 14:05
а теперь приду я и расскажу про сигнал dataChanged, к-ый не для таких случаев нужен, ибо тс извращенец - сразу найти место для вставки видимо слабо. qLowerBound да поможет вам в этом.


Название: Re: QTreeView + QAbstractItemModel после сортировки сбиваются индексы
Отправлено: Polt от Май 30, 2011, 12:20
не слабо, искал альтернативные шустро работающие варианты, не нашел, вопрос решен вставкой на нужную позицию.