Pull to refresh

Comments 42

Задолбали вы своими КДПВ
минусы замечены?
Вы думаете, это из-за картинки? Без нее было бы совсе сухо, разве нет?
С ней можно подумать мокро. Хабр — это что, pinterest?
Спасибо автор, классная подстава.
Ну не обессуть.
UFO just landed and posted this here
КДПВ — Картинка Для Привлечения Внимания

Статьи, в которых присутствует иллюстрация до ката, часто привлекают больше внимания, потому что люди очень любят визуальную информацию. Этим фактом иногда пользуются неподобающе: вставляют не очень тепло одетых дам и прочие изображения, которые не имеют к содержанию статьи никакого отношения, но моментально цепляют взгляд преобладающей мужской части аудитории сайта.
UFO just landed and posted this here
В статье про модели была картинка модели. Но народ не оценил игру слов.
По чесноку пользоваться QAbstractListModel проще, чем городить QStandardItemModel, хотя последнюю бывает тоже делаю если данные статичные полностью, но в последнее время уже почти не нужно этого.
Вот когда дело до деревьев доходит, то тут начинаются самые сложности :)
С деревьями да, интереснее. Я, в общем-то, даже сделал пример модели дерева, хотел включть сначала в статью, но в итоге, когда получилось 300 строк кода, а пример еще не был закончен, подумал, что если уж и рассказывать про это, то надо отдельную статью писать, про то как деревья делать. А тут больше такая критическая статья получилась. Если интерес у народа будет, напишу. Но пока в общем-то его не заметно особо.
Интересно, я с этими деревьями много матов в свое время поимел, а еще про прокси просится статья.
Да статья про девревья обязательно должна быть! Интерес однозначно есть.
А если гетерогенное дерево, то еще веселей.
UFO just landed and posted this here
Если вы про стиль написания, то я и сам им не очень доволен. Надеюсь, что со временем научучь писать лучше.

А если по поводу темы, то это как раз про Proxy модели. Там много всего интересного можно придумать, да.

А вот этот пост очень спорный. Хотя бы потому, что QStandardItemModel is not implemented as much efficient as possible, obviously.

При использовании же правильной QStringListModel и принятия мер против выкидывания оптимизирующим компиллятором обращений к QVector::operator[], результаты получаются немного другими:

mod msecs 211
vec msecs 68

UFO just landed and posted this here
UFO just landed and posted this here
Я тему знаю, поэтому прочитал с легкостью и удовольствием. А вот интересно, что думают те, кто еще не познал вкус связки Model-View (без Controller).

Не помешал бы классический наглядный пример БД — модель — виджет.
Ну что будет. Если вы явно Контроллера не выделите — он у вас расползется по классу модели и классу формы. Рано или поздно случится бардак. Проходили, знаем.
Можно подробнее про бардак? А то пока не сталкивался, но и таблицы были не особо гигантские, с курсорами и фреймами заморачиваться не приходилось.
Какие операции над таблицами доступны в вашем приложении? Были ли иерархические данные? Приходилось ли делать специфические эдиторы? Была ли возможность одновременного редактирования нескольких записей? Что насчет одновременной работы нескольких клиентских приложений?
Операции — банальный CRUD.
Иерархия имеется, через поле parent_id.
Эдиторы есть, но не особо специфичные — текст (много строк), картинка, элемент (объект из другой таблицы).
Одновременного редактирования в одном приложении не было. Но в принципе возможно — кто последний, тот и папа.
Несколько клиентов работают, блокировки записей отсутствуют. Трагедии в этом нет, поскольку данные разбиты по владельцам, а владельцы разбиты по иерархии. Удаление записей только админом, юзеры могут лишь прятать записи.
А не было ли в одном представлении данных из нескольких таблиц? Foreign key? Каскадное удаление? Транзакции?
Дык, самодельный ORM же. Все есть. Транзакции только примитивно используются — автокоммит + вручную для пакетных операций типа импорта данных… Есть быстрый, но неудобный ОРМ (все общение с БД прописано в модели), есть простой, но не шибко оптимальный. На практике простого вполне хватает.

А вы с какой целью интересуетесь?
Да в свое время наелись по самые помидоры с этим MV в Qt. Когда класс главного окна перевалил за 3000 строк и еще пяток разных моделей по тыще, а баги стали появляться быстрее чем их исправляли, релиз отъехал на пару месяцев по срокам. Кое-что отрефакторили, кое-что так и живет.
Зато удалось структуру бизнес-данных полностью вывести во внешний XML вместе с поведением (QScript). Т.е. «движок на Qt» почти ничерта не знает о бизнес-логике. Это позволило в дальнейшем наращивать бизнес-логику очень быстро. Причем используя менее квалифицированный ресурс.
Не совсем понял, почему главное окно оказалось перегружено кодом — оно же тупо отображает модели? Впрочем, всякое бывает.

У меня наоборот, довольно сложные и нудные модели, бизнес-логика где-то сбоку или на сервере, зато UI легок и приятен. И главное — сказочно гибок. Вот вздумалось перетасовать все виджеты и рассовать их по страницам — запросто, мышкой в дизайнере. И минимум кода, в основном всякие красивости и удобности, на работу не влияют.
Движок позволяет редактировать одновременно любое количество записей из любых таблиц, поддерживает для них закладки, переключаемые контексты, систему прав, имеет активную адресную строку по иерархии данных и еще кучу разнобразных рюшечек, придуманных воодушевленным специалистом по юзабилити. Одна беда — все это не было изначально запроектировано до мелочей, да и команда можно сказать набиралась опыта. Поэтому было реализовано как бог на душу положет.

Тем не менее в конце концов получилось прикольно, по крайней мере снаружи. А юзеру плевать что там внутри :)
Виджеты, это хорощо все. Но сами по себе они мало что из себя представляют. Где-то должна быть бизнес-логика, которая определяет поведение виджетов.
Локальная бизнес-логика работает с моделями. Серверная — с данными.
А поведение виджетов определяется моделями и самую малость кодом для отдельных случаев. Бизнес-логика к виджетам никакого отношения не имеет. Если уж так сильно надо порулить виджетами из скриптов — либо через модели, либо отдельная логика для UI.

Практика показывает, что как только UI связывается с данными через бизнес-логику — гибкость резко падает, а сложность поддержки возрастает. Приходится держать в голове всю цепочку «хранилище-данные-логика-представление», со всеми подвыпертами. А иначе сложность ограничена только одним звеном модель-хранилище, или модель-логика, или модель-представление. При этом звено модель-хранилище можно реализовать через ORM, и не париться. А модель-представление в Qt достаточно хорошо работает по дефолту.
Модель не может, грубо, сама себя сортировать и фильтровать. Кто-то должен инициировать эти действия. Моделью управляет пользователь. И этот код управления не может целиком быть перемещен на саму модель.
Это QAbstractTableModel не может, а мой субкласс может. Если захочет. Есть же стандартная сортировка по значенияем колонок виджета. А вообще это все при выборке из хранилища фильтруется и сортируется. В одной из реализаций все это делается в самом классе модели. В другой — в отдельной фабрике/контроллере моделей. Оба способа работают.
Это я еще проксями не пользовался. С ними наверняка гораздо интереснее. =)
Видел такое. Действительно, если не выделять четко контроллеры, то через некоторое время начинается полный бардак.

Другое дело, что интерфейс модели в Qt достаточно богатый.
Ну как богатый, мы когда дошли до пары десятков только собственных ролей в методе ::data() подумали что как-то все не очень ловко выходит.
А что не так с собственными ролями в data()? Я часто создаю их, когда в этом появляется необходимость. По-моему, это достаточно удобно, когда роль четко отражает род данных, которые по ней можно получить. Надо просто использовать единый их источник, чтобы ничто ни с чем не путалось.
Ну как это обычно бывает: сначала две-три роли, потом свитч, потом очень_длинный_свитч, потом рефакторинг и фабрика, создающая объекты разных классов-обработчиков под каждую роль.
Спасибо за статью.
P.S. Если интересно, могу рассказать о чем угодно подробнее по теме работы с моделями. Предложения принимаются.

Мне было бы интересно почитать про совместное использование QGraphicsView и QTableView c проксями для табличных представлений. Как пример, есть граф, его надо отображать в QGraphicsView, узлы с их характеристиками в первом QTableView, ветви — во втором. Ну и прокси для сортировки\фильтрации по таблицам.
Одни плюсы, а минусов, при этом, не замечено.
Очень смелое заявление. Да, все прекрасно работает, пока вы оперируете данными в объемах до ~1000 записей. Дальше начинаются проблемы.

Сходу могу накидать следующее:
1. Для сортировки и фильтрации предлагается QSortFilterProxyModel. Задумка хорошая но… Для сортировки и фильтрации данный класс выкачивает все сортируемые данные подмодели себе в память а затем внутри себя все это ворочает (а иначе просто не сделать). Если под этой моделью у вас лежит SQL-модель с десятками и сотнями тысяч записей — лучше забудьте о такой сортировке. Пишите сортировку и фильтрацию сами на SQL.
2. Иерархические модели. Поддержка иерархии есть (::parent()). Но такое ощущение, что прикручивали её сбоку после реализации прямоугольных моделей. На это намекает хотя бы тот момент что метод ::headerData(...) общий для всей модели (не зависит от индекса), а фактический набор колонок ::columnCount(...) зависит от узла иерархии.
3. Отрисовка иерархии в QTreeView. Прибито гвоздями, что визуальное отображение ветвей дерева делается всегда в нулевой колонке. Её можно кстати передвинуть в другое место, ветви тоже переедут. Может придирка, но реализация не выглядит продуманной.
4. QModelIndex. Класс так и провоцирует где-нибудь сохранить свой экземпляр с тем чтобы потом что-то с ним сделать. Этого делать ни в коем случае нельзя — индекс изменится при почти любом изменении модели. Есть QPersistentModelIndex для этих целей, но он тоже станет инвалидным, если модель переоткрыть, например.
5. Еще раз про SQL. Штатная реализация QSqlTableModel и QSqlQueryModel годятся только для простых случаев и небольших объемов данных. Если данных много и с ними нужны сложные манипуляции — пишите лучше сразу свои реализации под задачу. Со штатными только время потеряете.

В остальном MV вполне годный, пользоваться можно.
Про плюсы, это в контектсе использования MV вместо виджетов.

Пишите сортировку и фильтрацию сами на SQL.
Не всегда запрашивать сервер БД каждый раз, когда пользователь выполняет сортировку — рационально. Просто вытягивание по сети этих десятков и сотен тычяч записей может оказаться дольше, чем даже не очень умелая сортировка руками. Так что, тут не все так одназначно. Иногда можно правильно отсортировать данные при запросе к БД таким образом, что любую другую сортировку можно получить, не выполняя полную пересортировку. В общем, тут далеко не все так однозначно.

Иерархические модели.
О да, мне тоже всегда казалось, что они сделаны кривоваты. И этот parent() вечно не приткнуть никуда по-нормальному.

QModelIndex
Они хотели сделать макисмально легковесный класс. И у них, надо сказать, это получилось. В общем, надо, конечно, знать, как с ним работать, но ничего особо страшного нет. Вот реализация QPersistentModelIndex мне не очень-то нравится.

В общем, как и много где в Qt, есть много раздражающих моментов. Но, поскольку ничего лучше все равно нет, приходится пользоваться.
Не всегда запрашивать сервер БД каждый раз, когда пользователь выполняет сортировку — рационально. Просто вытягивание по сети этих десятков и сотен тычяч записей может оказаться дольше, чем даже не очень умелая сортировка руками. Так что, тут не все так однозначно. Иногда можно правильно отсортировать данные при запросе к БД таким образом, что любую другую сортировку можно получить, не выполняя полную пересортировку. В общем, тут далеко не все так однозначно.
Если вы сортируете или фильтруете в SQL-запросе, дишние данные остаются на сервере, не передаются. В чем плюс сортировки на SQL — повесил индексы и все работает как надо и памяти не расходует много. На клиенте придется либо иметь индексы (не знаю современных СУБД с внешними индексами) либо сортировать в памяти, т.е. все равно затащить все записи через сеть на клиента.
Это, в общем-то, зависит от того, сколько данных можно отфильтровать на сервере. Если количество данных, которые надо передать клиенту, велико, возможно их стоит скачать один раз, а не запрашивать каждый раз заново. Я просто сталкивался именно с такой постановкой задачи. Если на сервере удается эффективно отфильтровать большую чаасть данных, то вы, конечно, правы.
возможно их стоит скачать один раз, а не запрашивать каждый раз заново
Ну это уже тянет на классическую трехзвенку со всеми её плюсами и минусами
Sign up to leave a comment.

Articles