Название: Иерархическая модель Отправлено: KlimichKartorgnusov от Апрель 07, 2016, 11:23 Здравствуйте! Изучаю Qt совсем не давно. С табличными и списковыми моделями разобраться проблем не составило, но на счет древовидной модели возник тяжелый для меня вопрос... Все примеры которые я нашел, только окончательно меня запутали.
Проблема следующая. Есть класс "Доставка" который включает в себя свой номер доставки, дату и список поставленных товаров(класс Product). Код: class Product Код: class Delivery Нужно построить структуру такого типа: -Доставка 1. Дата: 01.02.2016 --товар 1 || 500 руб. || 10 шт. --товар 2 || 400 руб. || 20 шт. --товар 3 || 300 руб. || 10 шт. --товар 4 || 200 руб. || 30 шт. -Доставка 2. Дата: 15.02.2016 --товар 1 || 500 руб. || 10 шт. --товар 2 || 400 руб. || 20 шт. --товар 3 || 300 руб. || 10 шт. Две недели потратил на поиск нужного ответа, которого так и не нашел. Прошу вашей помощи! DiliveriesModel.h Код: #ifndef DILIVERIESMODEL_H DiliveriesModel.cpp Код: #include "DiliveriesModel.h" Название: Re: Иерархическая модель Отправлено: Igors от Апрель 07, 2016, 11:27 Ну а почему не "по пути наименьшего сопротивления"? Т.е. QTreeWidget и все дела
Название: Re: Иерархическая модель Отправлено: KlimichKartorgnusov от Апрель 07, 2016, 11:54 Ну а почему не "по пути наименьшего сопротивления"? Т.е. QTreeWidget и все дела Если использовать QTreeWidget, то нужно будет каждый раз строить дерево с нуля, а мне одну модель нужно будет использовать во многих местах. Название: Re: Иерархическая модель Отправлено: kambala от Апрель 07, 2016, 12:13 так а в чем проблема? наследуешься от QAbstractItemModel и определяешь обязательные методы:
Цитировать When subclassing QAbstractItemModel, at the very least you must implement index(), parent(), rowCount(), columnCount(), and data(). These functions are used in all read-only models, and form the basis of editable models. например, в rowCount() отдаешь количество для каждого уровня иерархии, т.е. для верхнего уровня — количество Delivery, для следующего — deliveredProducts_.size()Название: Re: Иерархическая модель Отправлено: ViTech от Апрель 07, 2016, 12:15 QAbstractItemModel + QTreeView подойдёт? Simple Tree Model Example (http://doc.qt.io/qt-5/qtwidgets-itemviews-simpletreemodel-example.html). Гуглить "qabstractitemmodel tree".
Название: Re: Иерархическая модель Отправлено: Igors от Апрель 07, 2016, 12:29 Если использовать QTreeWidget, то нужно будет каждый раз строить дерево с нуля, а мне одну модель нужно будет использовать во многих местах. Использовать или отображать? Если хочется "по всем канонам" - есть QTreeView. Но необязательно делать Вашу структуру данных моделью, можно напр задействовать QTreeWidgetItem::setData/data и/или хранить указатели на QTreeWidgetItem. Название: Re: Иерархическая модель Отправлено: KlimichKartorgnusov от Апрель 07, 2016, 12:43 так а в чем проблема? наследуешься от QAbstractItemModel и определяешь обязательные методы: Цитировать When subclassing QAbstractItemModel, at the very least you must implement index(), parent(), rowCount(), columnCount(), and data(). These functions are used in all read-only models, and form the basis of editable models. например, в rowCount() отдаешь количество для каждого уровня иерархии, т.е. для верхнего уровня — количество Delivery, для следующего — deliveredProducts_.size()Проблема в том что я не понимаю как реализовать index() и parent(). Не понятно какого родителя будет возвращать parent(), как бы все данные уже есть в листе дерева и из родителей остается только верхушка - пустой root index. index() должен создавать валидный QModelIndex() и возвращать его. Опять же не понимаю как образом это будет происходить в моем случае, как мне добираться до данных о Product. В примерах видно что лист дерева содержит информацию о своем родителе, свои данные и информацию о своих дочерних листах. У меня же все в одном классе Delivery. Название: Re: Иерархическая модель Отправлено: KlimichKartorgnusov от Апрель 07, 2016, 12:45 Если использовать QTreeWidget, то нужно будет каждый раз строить дерево с нуля, а мне одну модель нужно будет использовать во многих местах. Использовать или отображать? Если хочется "по всем канонам" - есть QTreeView. Но необязательно делать Вашу структуру данных моделью, можно напр задействовать QTreeWidgetItem::setData/data и/или хранить указатели на QTreeWidgetItem. Для этого созданы Q(Tree\Table\List)Widget. Q(Tree\Table\List)View разве можно использовать без модели? Название: Re: Иерархическая модель Отправлено: GreatSnake от Апрель 07, 2016, 14:28 Если использовать QTreeWidget, то нужно будет каждый раз строить дерево с нуля, а мне одну модель нужно будет использовать во многих местах. Почему тогда не использовать QStandardItemModel?Название: Re: Иерархическая модель Отправлено: KlimichKartorgnusov от Апрель 07, 2016, 14:43 Если использовать QTreeWidget, то нужно будет каждый раз строить дерево с нуля, а мне одну модель нужно будет использовать во многих местах. Почему тогда не использовать QStandardItemModel?Мне для задания нужно разобраться c QAbstract(Table/List/Item)Model. С первыми двумя разобрался в легкую, а как организовать дерево, я не понимаю. Не понимаю как будет работать data(), rowCount() и прочие обязательные для переопределения функции. Название: Re: Иерархическая модель Отправлено: Old от Апрель 07, 2016, 14:47 Мне для задания нужно разобраться c QAbstract(Table/List/Item)Model. С первыми двумя разобрался в легкую, а как организовать дерево, я не понимаю. Не понимаю как будет работать data(), rowCount() и прочие обязательные для переопределения функции. Вы вот это читали?http://doc.qt.io/qt-5.6/model-view-programming.html Вроде по картинкам все должно быть понятно. Название: Re: Иерархическая модель Отправлено: KlimichKartorgnusov от Апрель 07, 2016, 14:55 Мне для задания нужно разобраться c QAbstract(Table/List/Item)Model. С первыми двумя разобрался в легкую, а как организовать дерево, я не понимаю. Не понимаю как будет работать data(), rowCount() и прочие обязательные для переопределения функции. Вы вот это читали?http://doc.qt.io/qt-5.6/model-view-programming.html Вроде по картинкам все должно быть понятно. Ну да. С табличными и списковыми моделями понял. А с деревом к сожалению нет... Название: Re: Иерархическая модель Отправлено: __Heaven__ от Апрель 07, 2016, 14:59 Там же ссылка на простой пример (http://doc.qt.io/qt-5.6/qtwidgets-itemviews-simpletreemodel-example.html)
Название: Re: Иерархическая модель Отправлено: KlimichKartorgnusov от Апрель 07, 2016, 15:04 Там же ссылка на простой пример (http://doc.qt.io/qt-5.6/qtwidgets-itemviews-simpletreemodel-example.html) В примере фигурирует TreeItem. Он имеет родителя и дочернее элементы. Я не понимаю как свою структуру в которой все уже уложено применить. Мне нужно по другому организовать узел дерева? Название: Re: Иерархическая модель Отправлено: ViTech от Апрель 07, 2016, 15:07 Там же ссылка на простой пример (http://doc.qt.io/qt-5.6/qtwidgets-itemviews-simpletreemodel-example.html) Для одних это может и простой пример, а для других не очень :). Мне для задания нужно разобраться c QAbstract(Table/List/Item)Model. С первыми двумя разобрался в легкую, а как организовать дерево, я не понимаю. Не понимаю как будет работать data(), rowCount() и прочие обязательные для переопределения функции. Если сразу не понятно, то на пальцах тоже может не получится просто объяснить. Тут могут помочь в решении, но в "пустоту" трудно код писать. Рекомендую сделать простой проект, аналогично пример (http://doc.qt.io/qt-5.6/qtwidgets-itemviews-simpletreemodel-example.html), с вашими структурами данных, и всеми необходимыми методами, которые надо переопределить. Чтобы можно было его взять и туда код вписать. И помогающим будет проще, и помогаемым понятней :). Название: Re: Иерархическая модель Отправлено: kambala от Апрель 07, 2016, 15:08 ну добавь в Product поле типа Delivery *
Название: Re: Иерархическая модель Отправлено: KlimichKartorgnusov от Апрель 07, 2016, 15:45 Там же ссылка на простой пример (http://doc.qt.io/qt-5.6/qtwidgets-itemviews-simpletreemodel-example.html) Для одних это может и простой пример, а для других не очень :). Мне для задания нужно разобраться c QAbstract(Table/List/Item)Model. С первыми двумя разобрался в легкую, а как организовать дерево, я не понимаю. Не понимаю как будет работать data(), rowCount() и прочие обязательные для переопределения функции. Если сразу не понятно, то на пальцах тоже может не получится просто объяснить. Тут могут помочь в решении, но в "пустоту" трудно код писать. Рекомендую сделать простой проект, аналогично пример (http://doc.qt.io/qt-5.6/qtwidgets-itemviews-simpletreemodel-example.html), с вашими структурами данных, и всеми необходимыми методами, которые надо переопределить. Чтобы можно было его взять и туда код вписать. И помогающим будет проще, и помогаемым понятней :). Добавил код, ток что то не верится что за меня кто то будет делать. У меня такого никогда не прокатывало :) Название: Re: Иерархическая модель Отправлено: ViTech от Апрель 07, 2016, 16:35 Как один из возможных вариантов...
Со структурой такого типа как QList<Delivery> deliveries_ получается всего два уровня в "дереве". Сама структура Delivery не "деревянная", значит QModelIndex::internalPointer() задействовать именно как указатель особо не получится, но оно не сильно и нужно. Вместо этого необходимо где-то хранить уровень дерева, можно в том же QModelIndex::internalPointer(), как int 1,2 (а лучше enum завести). Навскидку: Код
В остальных методах действовать аналогично. Где в примере использовалось Код приводить к уровню дерева Код
В Код опять же из индекса QModelIndex &index и его internalPointer() получать уровень дерева и работать соответственно с Delivery или Product. Если internalPointer() слишком кривое место для хранения уровня дерева, то найти получше :). Название: Re: Иерархическая модель Отправлено: ViTech от Апрель 07, 2016, 16:46 Хотя для второго уровня надо ещё родительский индекс правильно определять, чтобы знать из какого Delivery брать Product. Либо с указателями работать, либо ещё как-то извращаться.
В общем-то если уровней всего два, то если internalPointer() == NULL, то находимся в корне, работать с QList<Delivery> deliveries_, если internalPointer() == -1, то это лист с Product, иначе указатель на соответствующий Delivery. Куда-то в этом направлении копать :). Можно ещё в этом internalPointer() хранить индекс Delivery в списке QList<Delivery>. Если -1, значит в корне. Название: Re: Иерархическая модель Отправлено: __Heaven__ от Апрель 07, 2016, 16:50 ну добавь в Product поле типа Delivery * +1Название: Re: Иерархическая модель Отправлено: ViTech от Апрель 07, 2016, 16:56 Не должны всякие деревянные модели на исходные структуры данных влиять. Это модель должна под исходные данные подстраиваться, а не наоборот. Название: Re: Иерархическая модель Отправлено: KlimichKartorgnusov от Апрель 07, 2016, 17:06 Хотя для второго уровня надо ещё родительский индекс правильно определять, чтобы знать из какого Delivery брать Product. Либо с указателями работать, либо ещё как-то извращаться. В общем-то если уровней всего два, то если internalPointer() == NULL, то находимся в корне, работать с QList<Delivery> deliveries_, если internalPointer() == -1, то это лист с Product, иначе указатель на соответствующий Delivery. Куда-то в этом направлении копать :). Можно ещё в этом internalPointer() хранить индекс Delivery в списке QList<Delivery>. Если -1, значит в корне. Это все интересно и выглядит логично, но я все равно не въезжаю как представление строит модель. Представление дергает функцию data(). Как? Рекурсивно? Как она догадывается от структуре исходных данных. Простите пожалуйста меня за мою тупость, просто хочется все разъяснить для себя. Поправка. rowCount() и columnCount() за это отвечают ? Название: Re: Иерархическая модель Отправлено: __Heaven__ от Апрель 07, 2016, 17:21 rowCount сообщает, есть ли потомки.
если я вас правильно понял Название: Re: Иерархическая модель Отправлено: Igors от Апрель 07, 2016, 17:27 ну добавь в Product поле типа Delivery * и Product стал неперемещаемым...Это все интересно и выглядит логично, но я все равно не въезжаю как представление строит модель. Представление дергает функцию data(). Как? Рекурсивно? Как она догадывается от структуре исходных данных. Корневые эл-ты - просто по индексу строки. Чилдренов - от корневого (rowCount(QModelIndex)). И представление не строит - всего лишь опирается на методы модели.Ни разу еще не писал свою модель - не было приличных данных. А тогда проще не подстраивать "оригинал" под модель, а просто копировать его в удобный QTreeWidget :) Название: Re: Иерархическая модель Отправлено: ViTech от Апрель 07, 2016, 17:28 Это все интересно и выглядит логично, но я все равно не въезжаю как представление строит модель. Представление дергает функцию data(). Как? Рекурсивно? Как она догадывается от структуре исходных данных. Простите пожалуйста меня за мою тупость, просто хочется все разъяснить для себя. Давно я с этим возился, уже позабывал всё :). Чтоб не врать и вводить в заблуждение, лучше посоветую собрать приложение хотя бы из того же примера (http://doc.qt.io/qt-5/qtwidgets-itemviews-simpletreemodel-example.html), поставить точки останова в методы и посмотреть, когда, что и в каком порядке вызывается. А так в общем да, представление вызывает метод data() модели, когда надо что-то отобразить в ячейке с заданным индексом. Так же вызывает и другие методы, когда определяет свои размеры row column и прочее. Само представление к исходным данным не обращается, ему нужны QVariant, которые предоставляет метод data() модели. Структура исходных данных формируется в виртуальных методах QAbstractItemModel, особо важные из них чистые виртуальные, поэтому их и надо переопределять, чтобы дать минимальное представление о модели. Подробности в документации :). Название: Re: Иерархическая модель Отправлено: KlimichKartorgnusov от Апрель 07, 2016, 17:35 Это все интересно и выглядит логично, но я все равно не въезжаю как представление строит модель. Представление дергает функцию data(). Как? Рекурсивно? Как она догадывается от структуре исходных данных. Простите пожалуйста меня за мою тупость, просто хочется все разъяснить для себя. Давно я с этим возился, уже позабывал всё :). Чтоб не врать и вводить в заблуждение, лучше посоветую собрать приложение хотя бы из того же примера (http://doc.qt.io/qt-5/qtwidgets-itemviews-simpletreemodel-example.html), поставить точки останова в методы и посмотреть, когда, что и в каком порядке вызывается. А так в общем да, представление вызывает метод data() модели, когда надо что-то отобразить в ячейке с заданным индексом. Так же вызывает и другие методы, когда определяет свои размеры row column и прочее. Само представление к исходным данным не обращается, ему нужны QVariant, которые предоставляет метод data() модели. Структура исходных данных формируется в виртуальных методах QAbstractItemModel, особо важные из них чистые виртуальные, поэтому их и надо переопределять, чтобы дать минимальное представление о модели. Подробности в документации :). Большое вам спасибо. Вы дали хороший пинок в сторону решения моей проблемы. Название: Re: Иерархическая модель Отправлено: KlimichKartorgnusov от Апрель 07, 2016, 17:38 ну добавь в Product поле типа Delivery * и Product стал неперемещаемым...Это все интересно и выглядит логично, но я все равно не въезжаю как представление строит модель. Представление дергает функцию data(). Как? Рекурсивно? Как она догадывается от структуре исходных данных. Корневые эл-ты - просто по индексу строки. Чилдренов - от корневого (rowCount(QModelIndex)). И представление не строит - всего лишь опирается на методы модели.Ни разу еще не писал свою модель - не было приличных данных. А тогда проще не подстраивать "оригинал" под модель, а просто копировать его в удобный QTreeWidget :) Хоть перетаскивания и не будет у модели, вполне логично иметь обратную связь Product с его Delivery. Спасибо. Название: Re: Иерархическая модель Отправлено: __Heaven__ от Апрель 07, 2016, 17:41 Рекомендую особое внимание уделить методам parent и index. У меня при изучении была проблема с ними. Скорее всего, вам просто достаточно будет передрать их из примера с небольшими корректировками.
Название: Re: Иерархическая модель Отправлено: Jaxx от Апрель 08, 2016, 10:01 У меня была похожая проблема. http://www.prog.org.ru/topic_30005_0.html (http://www.prog.org.ru/topic_30005_0.html)
Может поможет. Название: Re: Иерархическая модель Отправлено: Igors от Апрель 08, 2016, 10:32 У научного работника мелькнула здравая мысль
Не должны всякие деревянные модели на исходные структуры данных влиять. Это модель должна под исходные данные подстраиваться, а не наоборот. Которая впрочем сразу растворилась в хоре "передрать". Ну а действительно, вот исходные данныеКод: class Delivery Так ли уж хорошо делать исходные данные моделью, нет ли других подходов? Название: Re: Иерархическая модель Отправлено: kambala от Апрель 09, 2016, 23:27 в тот же вечер я быстро написал маленький пример и никак не мог понять почему он не работает. начал сравнивать с Simple Tree Model — все было сделано аналогично (только там полноценная модель дерева у них строится, а у меня на if'ах). только что нашел ошибку: в реализации data() у меня отсутствовало игнорирование всех прочих ролей кроме DisplayRole :)
ну добавь в Product поле типа Delivery * это кстати не понадобилось, сохранил указатель в internalPointer()могу выложить, если еще нужно. Название: Re: Иерархическая модель Отправлено: KlimichKartorgnusov от Апрель 10, 2016, 09:42 в тот же вечер я быстро написал маленький пример и никак не мог понять почему он не работает. начал сравнивать с Simple Tree Model — все было сделано аналогично (только там полноценная модель дерева у них строится, а у меня на if'ах). только что нашел ошибку: в реализации data() у меня отсутствовало игнорирование всех прочих ролей кроме DisplayRole :) ну добавь в Product поле типа Delivery * это кстати не понадобилось, сохранил указатель в internalPointer()могу выложить, если еще нужно. Нужно конечно, выложите пожалуйста. Название: Re: Иерархическая модель Отправлено: kambala от Апрель 10, 2016, 12:29 структура данных взята упрощенная, но она аналогична ТСовской
Код
Название: Re: Иерархическая модель Отправлено: KlimichKartorgnusov от Апрель 10, 2016, 16:43 структура данных взята упрощенная, но она аналогична ТСовской Код
Большое спасибо! Самый человеко понятный пример которой я видел :) |