Название: HowTo: Модель для неупорядоченных данных Отправлено: Eugene Efremov от Май 01, 2009, 19:13 Модель для неупорядоченных данных
Статью пришлось разбить на две части из-за технического ограничения в 20000 знаков для одного сообщения. Аттач с примером прикреплен к первой части, но его требуемое правилами описание, в силу нахождения его в конце статьи, оказалось во второй. Будьте внимательны. Disclaimer Эта статья создана по результатам моей переписки (http://www.prog.org.ru/topic_7622_0.html) с Константином (http://www.prog.org.ru/index.php?action=profile;u=4679). Целью написания послужило желание разобраться в использовании Qt'шной реализации шаблона MVC (http://ru.wikipedia.org/wiki/MVC) — особенно в части добавления новых данных. Сразу оговорюсь — я пока не считаю свои знания в этой области достаточно удовлетворительными. Статья содержит ошибки — как технические, так и концептуальные. И скажу прямо — я сильно рассчитываю на помощь читателей в их поиске и исправлении. Вступление В реализованном в Qt варианте MVC предполагается, что хранящиеся в модели данные упорядочены: представление взаимодействует с ней посредством индексов (http://www.doc.crossplatform.ru/qt/4.4.3/qmodelindex.html), содержащих номера строки и столбца. Между тем, в природе существует множество источников данных, порядок элементов в которых, в лучшем случае, не имеет значения, в худшем — вообще не подлежит определению. И если при просмотре модели мы, как правило, можем выдать эти данные в неком произвольном (точнее — обусловленном текущий выборкой из источника данных) порядке, то при добавлении/изменении таких данных этот порядок может меняться совершенно непредсказуемым образом. Это может создать некоторые сложности. Мы рассмотрим простейший вариант такого источника — хэш (если конкретно — то QHash<QString, QString>) и попробуем построить для него модель, поддерживающую вставку и редактирование как значений, так и ключей. Отметим для этого примера дополнительное ограничение, также встречающиеся достаточно часто — ключи должны быть уникальны. 1. Внутренняя структура модели. Итак, мы строим модель для хэша строк. Очевидно, ему будет соответствовать таблица в две колонки (для ключа и значения), каждая строка которой соответствует одному элементу хэша. Значит, мы унаследуем модель от QAbstractTableModel (http://www.doc.crossplatform.ru/qt/4.4.3/qabstracttablemodel.html). Поскольку хэш — достаточно простая структура, мы можем хранить его непосредственно в самой модели. Кроме того, нам нужно как-то фиксировать добавление в таблицу пустых строк (мы не можем сразу занести их все в хэш из-за требования уникальности ключей). Для этого добавим счетчик таких строк (соответственно, rowCount будет возвращать сумму count хэша и этого счетчика). И того, получаем такую заготовку для нашей будущей модели: Код
Кроме того, нам потребуется как-то преобразовывать строки и индексы, которые будет нам отдавать модель, в ключи нашего хэша. Введем для этой цели закрытые служебные ф-ции: Код
Теперь, определившись с доступом к хэшу, мы можем перейти к реализации интерфейса. Лирическое отступление Для ускорения доступа мы могли бы сохранять ключи в отдельном массиве и обращаться к его индексам. И в реальности, скорее всего, так бы и поступили. Но это лишило бы ценности наш пример, поскольку данные перестали бы быть неупорядоченными. 2. Доступ к данным. Как известно (http://www.doc.crossplatform.ru/qt/4.4.3/model-view-model-subclassing.html), для реализации readonly доступа нам достаточно реализовать flags, data, headerData и *Count. Их реализации — кроме data — очевидны. На последней остановимся подробнее: Код
Мы получаем ключ с помощью определенной ранее id2key и проверяем его наличие. Отсутствие ключа означает, что мы имеем дело со свежевставленным пустым элементом, которого в хэше нет. Во всех остальных случаях это обычный элемент хэша. Лирическое отступление Может возникнуть вопрос — почему мы не храним ключи в индексах? Причин тому две. Во-первых, по каким-то неведомым мне причинам, индексы не предполагают хранения в них произвольного QVariant. Они разрешают хранить или указатели, или целые числа. Так что — если бы мы захотели хранить в нем строки, нам бы пришлось, на деле, хранить их где-то еще. Т.е, фактически, создавать тот же массив ключей, который мы уже не захотели создавать в предыдущей части. А во-вторых — это мало что дает. Просто поиск соответствия стоки и ключа переместится в ф-цию index, которую еще и перегружать придется... 3. Добавление элементов. Стандартный интерфейс. Для добавления элементов в модель предусмотрен метод insertRows (для удаления, соответственно, removeRows — но его реализация очевидна). И здесь следует сделать важное замечания. Этот метод не предоставляет средств для добавления в модель новых данных. Т.е., если мы хотим использовать для добавления новых элементов стандартный механизм — мы должны с помощью insertRows создать новую строку, и только затем уже — добавлять туда данные, вызывая setData для каждой ячейки. Это, кончено, очень неудобно, и мы еще вернемся к этому вопросу. Сейчас для нас важно другое: строки, созданные insertRows, должны быть пустыми: Код
И здесь мы сталкиваемся с еще одной странностью всей этой системы. Но в данном случае эта странность идет нам на пользу. Внимательный читатель мог бы заметить, что переменная row, фактически, нами игнорируется: мы увеличиваем m_empty, что эквивалентно вставки новой строки в конец модели — независимо от значения row. Действительно, если бы мы везде в этой ф-ции заменили row на 0 — ничего бы не изменилось. Иными словами для beginInsertRows/endInsertRows совершенно безразлично, куда на самом деле вставляются новые столбцы — лишь бы их было нужное количество. Лирическое отступление Возникает вопрос — почему insertRows не поддерживает добавление данных? Причина проста: QAbstractItemModel не знает сколько и каких данных мы будем вставлять, и куда. Она не знает, сколько у нас столбцов в модели, соответствует элемент модели строке или же ячейке и т.д. Соответственно, не может и предоставить прототип метода, однозначно отвечающего нашим запросам. 4. Добавление элементов. Расширение интерфейса. Как было сказано выше, добавлять новые элементы, пользуясь стандартным интерфейсом, крайне неудобно (а также — крайне неэффективно). Устранить этот недостаток можно, добавив в интерфейс ф-цию, принимающую пару ключ/значение и добавляющую ее в хэш. Простейшая реализация этой ф-ции будет, очевидно, примерно такой: Код
Здесь мы снова используем свойство beginInsertRows/endInsertRows, позволяющее вставлять данные куда угодно. Но с учетом этого «снова», нельзя ли вместо этого повторно использовать уже готовый код — insertRows? Можно, но результат оставляет желать лучшего: Код
Работа, которую мы здесь проделали, достаточно бессмысленна: сперва мы вызвали insertRows и увеличили m_empty, затем мы уменьшили m_empty обратно и лишь после этого вставили значение. (Кроме того, раз мы не знаем, куда именно мы ее вставили, мы должны сигнализировать об изменении всех непустых данных модели. Но это, как раз, вполне ожидаемо). Но это решение было бы вполне разумным, если insertRows вызвали до нас и m_empty уже имеет отличное от нуля значение. В этом случае мы просто избавляемся от существующей пустой строки в модели. Таким образом, оптимальный вариант будет таким: мы реализуем — как приватные методы — оба варианта и вызываем из insertItem тот либо другой в зависимости от значения m_empty: Код
В этом коде, кроме всего вышесказанного, часто повторяющейся вызов m_hash.contains(key) вынесен в открытый метод hasItem: пользователям модели тоже будет полезно знать, присутствует ли в ней тот или иной элемент. Лирическое отступление Почему с использованием стандартных интерфейсов возникли такие сложности, что нам пришлось вводить собственный? Причин тому две. Одну из них мы уже упоминали выше: система не знает, что у нас за модель и как в нее вставлять данные. Ее стандартный интерфейс ориентирован лишь на отдельную обработку каждой ячейки данных. И, соответственно, довольно криво работает в ситуациях, когда элемент занимает больше одной ячейки (а он, как правило, занимает целую строку). Вторая причина в том, что в реализации Model/View/Controller, с которой нам приходится работать, одна из этих трех базовых компонент попросту отсутствует. У нас нет контроллера. На замену ему предлагаются делегаты, которые, кроме того, берут на себя также и львиную долю работы представления (все в одну кучу, ага...). Но они предлагают интерфейсы лишь для изменения существующих элементов. Если мы хотим добавить новый — получаем дырку, которую и приходится затыкать взятыми откуда попало подручными средствами... 5. Изменение существующих данных. Наконец, мы приходим к последнему из необходимых элементов стандартного интерфейса — ф-ции setData. Если бы мы разрешали редактирование только значений (что, в реальности, скорее всего, было бы оптимальным выбором) — мы могли бы реализовать ее гораздо раньше. Но мы хотим также разрешить изменение с ее помощью ключей. А единственный способ сделать это для хэша — удалить существующий ключ, заменив его новым. А значит нам придется использовать интерфейс, который мы определили в предыдущем разделе. При редактировании ключа мы проверяем, находится ли редактируемая строка в хэше. Если да — сперва удаляем ее, затем вставляем заново с новым ключём и старым значением. Если она пустая — сразу вставляем с пустым значением. И еще тонкий момент — прежде, чем это делать мы должны убедиться, что новый ключ не совпадает ни с одним из существующих, иначе при вставке в хэш он его затрет: Код
Помимо этого, мы, по аналогии с вставкой, можем (точнее — должны) определить интерфейс для быстрого изменения значений по ключу. Как и в случае с добавлением нового ключа, мы не знаем, какая именно строка здесь изменилась. Поэтому, мы сигнализируем о возможном изменении всех значений: Код
Еще одним дополнением будет возможность задать весь хэш (метод setDataSource — реализация очевидна). Наиболее очевидная область использования этого функционала — начальная инициализация модели. 6. Поиск ключей. В принципе, на этом нашу модель уже можно было бы считать готовой. Однако, для полноты не мешало бы иметь механизм, позволяющий получить индекс по заданному значению ключа. И такой механизм у нас есть, хотя выглядит он не слишком красиво. Это метод QAbstractItemModel::match (http://www.doc.crossplatform.ru/qt/4.4.3/qabstractitemmodel.html#match). Однако, стандартная реализация этого метода будет, очевидно, работать с нашей моделью весьма неэффективно. Поэтому мы переопределим этот метод, реализовав для ключей более эффективный поиск: Код
Нам здесь все равно приходится искать позицию ключа в списке. Но даже это будет быстрее, чем многократный вызов data, имеющий место в исходной реализации. Кроме того, отсутствие ключа мы обнаружим сразу. Лирическое отступление Приведенный код не слишком красив — приходится проверять множество условий, чтобы выбрать из всех вариантов единственный нужный. Причина этого ясна: функции передается слишком много параметров. Это плохо, но мы с этим мало что можем сделать — здесь опять-таки нужно править QAbstractItemModel. Так или иначе, на этом реализацию самой модели можно считать законченной. Мы не рассмотрели вопросы, связанные с выделением и поддержкой drag`n`drop, но это — даже если оставить в стороне вопрос, какое отношение drag`n`drop вообще имеет к модели — слишком большая тема, чтобы ее можно было полноценно описать в рамках данной статьи. Кроме того, поскольку мы уже определили необходимые интерфейсы, преодолевающие сложности, связанные с неупорядоченностью данных модели, а значит — для реализации этого дополнительного функционала мы можем использовать уже их. С учетом этого, реализация будет подобна таковой для любой другой сложной модели — что не имеет прямого отношения к тематике данного HowTo. Посему, будем считать модель готовой к употреблению, и рассмотрим теперь некоторые аспекты ее использования. продолжение см. ниже... Название: HowTo: Модель для неупорядоченных данных Отправлено: Eugene Efremov от Май 01, 2009, 19:14 Модель для неупорядоченных данных
Статью пришлось разбить на две части из-за технического ограничения в 20000 знаков для одного сообщения. Аттач с примером прикреплен к первой части, но его требуемое правилами описание, в силу нахождения его в конце статьи, оказалось во второй. Будьте внимательны. 7. Контроллер. Как уже отмечалось выше — нормальных контроллеров у нас нет. Поэтому возникает соблазн реализовать соответствующий функционал где попало — например прямо в методах главного окна. Однако эти деструктивные поползновения смешать данные с представлением мы отбросим — в конце концов, если Qt не озаботилось предоставить нам контроллер, нам никто не мешает сделать его самим. Поскольку интерфейс для редактирования элементов уже реализован связкой представление/делегат, нам нужен только интерфейс для их добавления и удаления: Код
Отметим, что нам даже не нужно передавать модель в конструктор — мы можем получить ее из view. И то же самое view послужит нам в качестве родительского объекта. Реализация insertItem с использованием расширенного интерфейса нашей модели тривиальна: Код
Для removeItem же вообще достаточно стандартного интерфейса. Удаляем мы текущий столбец, получая его из представления: Код
Единственным недостатком такой схемы будет то, что представление об этом контролере ничего не знает, а значит — средств для его вызова нам не предоставляет. Мы, конечно, можем реализовать собственное представление, но значительно проще будет обернуть существующее представление в виджет, добавив туда же пару кнопок для управления контроллером. Фактически, такой виджет тоже будет играть роль представления — только более высокого уровня. Лирическое отступление Обращает на себя внимание, что контроллер у нас теперь занимает болше одного объекта: помимо нашего HashController, часть функций контроллера взял на себя QAbstractItemDelegate (http://www.doc.crossplatform.ru/qt/4.4.3/qabstractitemdelegate.html) скрытый в недрах представления. Более того, нам ничего не мешает, например, разделить HashController на две части — одну для удаления элементов, другую — для добавления. В принципе, это хорошо. Для контроллеров, фактически, реализуется компонентный подход. Собственно, именно желание разбить контроллер на компоненты и привело, скорее всего, авторов Qt к концепции делегатов. Но это уже другая история... 8. Использование в контроллере стандартного интерфейса модели. Одним из требованием к модели была возможность полного доступа к ней с использованием только стандартного интерфейса QAbstractItemModel. Посмотрим, сможем ли мы реализовать функционал нашего контроллера, используя только стандартный интерфейс. Фактически, нам нужно переписать только insertItem, поскольку во всех других случаях мы уже его используем. Мы можем реализовать этот функционал, ничего не зная о ключах, но нам придется задействовать match со всем ее недостатками: Код
Мы видим, что код получился крайне громоздким и неудобочитаемым. Обращает на себя внимание, что для вставки новой пары ключ значение, нам пришлось не только два раз вызвать setData, но и дважды провести поиск, поскольку после вставки ключа индексы стали недействительны! Единственная ценность проведенного изменения в том, что теперь HashController может работать с любой моделью, а не только с нашей. Учитывая, что писался он именно под HashModel, эта ценность представляется весьма сомнительной... Так что, для реальной работы, конечно, стоит использовать расширенный интерфейс модели, раз уж мы его определили. Истинный же смысл этого написания этого варианта контроллера был в том, что мы убедились: наша модель работает и полностью поддерживает стандартный интерфейс. А значит, на этом работу по ее написанию можно считать законченной. Дополнение. Описание вложения. Прилагаемый код содержит классы HashModel, HashController а также простейший вариант виджета для обертки представления (по совместительству выступает в качестве главного окна примера). Также прилагается простенький диалог для ввода пары ключ/значение. Класс HashController может быть откомпилирован в обоих вышеописанных вариантах. По умолчанию он использует расширенный интерфейс HashModel, для использования стандартного интерфейса необходимо установить макрос HC_USE_STANDART. Требования к версии Qt: не ниже 4.4 (в диалоге используется QFormLayout (http://)). Проверено под Windows 2003 в Qt 4.4.1, в компиляторе mingw, gcc version 3.4.5 Исходный код прикреплен к первой части статьи (см. выше). Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: ритт от Май 01, 2009, 23:47 бросил читать на четвёртом пункте. возмутительно! статью следовало назвать "я так ничерта и не понял", а не "howto".
важные моменты: QHash не сохраняет последовательность ключей; QModelIndex не хранит данные; что не так с ролями и с каких пор подсказки вьюхе считаются нонсенсом?; стандартный интерфейс предназначен для _самодостаточных_ моделей, а не для кастратов каких-то с зависимостями от прихотей юзверя, а для кастратов "расширенный" интерфейс подойдёт... наверняка, далее такая же чушь, но читать дальше я увольняюсь. Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: pastor от Май 02, 2009, 10:13 Константин, я бы небыл настолько категоричен в отношении к статье. Eugene Efremov попытался написать её, за что ему отдельное спасибо. Человек только учится. Все неточности в статье можно обсудить и исправить - будет польза и форуму и автору. имхо
Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: Eugene Efremov от Май 02, 2009, 17:36 статью следовало назвать "я так ничерта и не понял" Вообще-то, я достаточно ясно сказал про это в самом начале стати. И писать ее взялся именно с целью понять. Более того, ранее, в нашем обсуждении этого вопроса, я достаточно ясно высказался, что именно я собираюсь сделать: меня этот тред начинает утомлять... Жаль. Хотя, в принципе, понимаю, что таким дотошным выяснением деталей можно достать кого угодно. :) Тогда предлагаю сделать так. Я иду в тему «Уроки и статьи (http://www.prog.org.ru/board_61_0.html)», пишу там — в меру своего текущего понимания — заготовку для обещанного howto, после чего общими усилиями доводим его до ума. На готовом примере с описанием все ошибки и неточности сразу будут видны. А в конечном счете получится (надеюсь) что-то, полезное для всего форума. Никаких возражений против этого я не встретил. И писал — зная, что моих знаний и опыта для полноценного освещения вопроса явно недостаточно — именно в расчете на дальнейшее сотрудничество и помощь в исправлении ошибок. А не на вопли о том, что это «возмутительно». QHash не сохраняет последовательность ключей; Я где-то утверждал обратное? Наоборот, я написал что выбрал его — в качестве иллюстрации проблемы — именно по причине неупорядоченности содержащихся в нем данных. Единственное, на что я закладываюсь — это на то, что пока хэш не меняется QHash::keys возвращает всякий раз одинаковый список. Естественно, что как только мы модифицируем хэш, этот список станет другим. Вообще, способ, которым я установил связь между этим хэшем и индексами мне самому не нравится, как многое другое в этой модели. Так что, если кто-нибудь предложит другой вариант — я ему буду только благодарен. QModelIndex не хранит данные; Для чего тогда нужны QAbstractItemModel::createIndex принимающий целые числа или указатели, а также QModelIndex::internalPointer и QModelIndex::internalId их возвращающие? что не так с ролями Они реализованы через enum и тянут за собой повторяющийся switch/case во все места, где используются. и с каких пор подсказки вьюхе считаются нонсенсом?; Смешение данных и представления. стандартный интерфейс предназначен для _самодостаточных_ моделей, а не для кастратов каких-то с зависимостями от прихотей юзверя, а для кастратов "расширенный" интерфейс подойдёт... Мда. На это даже и не знаю что сказать. Осмысленного утверждения, с которым можно согласиться или оспорить я здесь не увидел. Одни эмоции. :( читать дальше я увольняюсь. Очень жаль. Я рассчитывал на конструктивный диалог. Просьба ко всем читателям: пожалуйста, не надо писать сюда только для того, чтобы сообщить, что автор дурак, а в статье написана полная чушь. Мне это и без вас известно. Если вы видите конкретную ошибку — будь то в коде, тексте статьи или общих положениях, на которые это все опирается — сообщите о ней. Если при этом еще укажите, как ее исправить — будет совсем хорошо. Если вы видите спорное или неточное утверждение и хотите его обсудить, или предлагайте внести в статью те или иные изменения — welcome. Но если вы пришли только за тем, чтобы сказать, что все плохо, и никаких конкретных предложений, как это все исправить, у вас нет — пожалуйста, идите с этим в какое-нибудь другое место... Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: Eugene Efremov от Май 02, 2009, 18:35 Все неточности в статье можно обсудить и исправить - будет польза и форуму и автору. Спасибо за поддержку.Выражаю надежду, что на форуме найдутся люди, готовые этим заняться... Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: ритт от Май 02, 2009, 19:59 гг...я был послан )
pastor, Eugene Efremov попытался написать своё негативное отношение к реализации model-view в Qt, а это не больно-то связано с названием статьи. тут ситуация примерно как с давешним вопросом про QString ("что это за поддержка unicode такая, если она даже стандартный wchar_t не понимает?!") - сначала эмоции, а потом думалка. Цитировать вопли о том, что это «возмутительно» ну, правильно. я возмущён - вот и вопию. к тому же, в начале статьи ссылка на меня и на наш диалог, хотя, в статье используются лишь собственные домыслы, а полуается, что и я причастен к этому...Цитировать Для чего тогда нужны QAbstractItemModel::createIndex принимающий целые числа или указатели, а также QModelIndex::internalPointer и QModelIndex::internalId их возвращающие? мб стоило сначала прояснить это для себя? подсказка: где используется createIndex(...)?Цитировать Цитировать что не так с ролями Они реализованы через enum и тянут за собой повторяющийся switch/case во все места, где используются. Цитировать Цитировать и с каких пор подсказки вьюхе считаются нонсенсом?; Смешение данных и представления. далее: ты сетуешь на то, что в модель нельзя вставить поизвольный объём данных "одним махом". давай прикинем - абстрактная модель знать не знает сколько ты (разработчик) собираешься сделать столбцов в строке, будет ли это количество столбцов одинаковым для каждой строки и, тем-более, _сколько_столбцов_ будет в строках, которых ещё не существует, но пользователь _может_ их создать. и ты на месте модели хотел бы иметь метод insertRow(int pos, void* data0, void* data1, ..., void* data40)? а потом какой-то умник создаёт строку с 50-ю столбцами и возмущается, что его задача не предусматривается абстрактным интерфейсом. с другой стороны, если пользователю потребуется создать строку с произвольным содержимым, чего мне беспокоиться о том, что для её вставки потребуется 40-50 вызовов setData(...)? да пусть хоть 150, если я всё-равно не могу предусмотреть эффективного интерфейса для данной задачи. но если могу, то почему просто его не добавить, как это сделано в QSqlTableModel (bool QSqlTableModel::insertRecord ( int row, const QSqlRecord & record ))? ах, вьюха не знает никакого insertRecord() модели. а разве вьюха добавляет/удаляет строки в/из модель/и?! короче, каждое лирическое отступление в статье - это иллюстрация непонимания того или иного момента. а лажать троллей - это зря, с этим на лор. зы. быть может, я не прав, возможно, в мире существуют настолько удобные и универсальные реализации MV(C), что кутэшная рядом с ними - настоящее дерьмо, но я таких пока не встречал. сделают iv-ng, учтут недочёты предыдущей реализации - хорошо. а пока что и текущей реализации достаточно - только нужно документацию внимательно читать, если чего-то не понимаешь. Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: pastor от Май 02, 2009, 20:41 pastor, Eugene Efremov попытался написать своё негативное отношение к реализации model-view в Qt Кстате не все довольны MV в Qt и в самом Trolltech ))). Так что для меня это не новость )) Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: ритт от Май 02, 2009, 20:51 и я не говорил, что прямо-таки доволен, но в Qt других реализаций модель-вью нет - работаем с тем, что имеется...
Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: johnny от Май 02, 2009, 22:15 to Eugene Efremov
Я тоже пытаюсь разобраться в qt-моделях, с интересом почитал ваш "крик души" :). Если можно, поясните несколько моментов: 1. Вы пытаетесь обеспечить вставку произвольного числа строк. Я так и не понял - зачем? Ну разрешайте вставку тока одной, если идет попытка вставить больше - возвращайте false. 2. "Иными словами для beginInsertRows/endInsertRows совершенно безразлично, куда на самом деле вставляются новые столбцы — лишь бы их было нужное количество." - мне представляется, что подписчики этих сигналов используют информацию о месте вставки чтобы избежать ненужных запросов данных - им потребуется перерисовать тока вставленные столбцы. Если передавать неверную инфу - будут грабли с отрисовкой. 3. "Одним из требованием к модели была возможность полного доступа к ней с использованием только стандартного интерфейса QAbstractItemModel" - я не понял, почему мы должны использовать интерфейс QAbstractItemModel в реализации метода нашего же класса? Какие выгоды мы от этого получаем - код же просто кошмарный... PS Заинтересовался Qt тока позавчера, так что сильно не пинайте :) Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: johnny от Май 02, 2009, 22:35 Цитировать Несомненно, читатель уже обратил внимание на уродливую связку swicth/case. Ну тут еще вопрос - что лучше. Если избавиться от role, то получится куча функций вида: data(), icon(), background(), tooltip(), whatWhis(), ... так по крайней мере вся логика получения данных в одном месте. и насчет Цитировать Во-первых, вся система явно ориентирована на отдельную обработку каждой ячейки данных. И, соответственно, довольно криво работает в ситуациях, когда элемент занимает больше одной ячейки (а он, как правило, занимает целую строку). Я ради интереса почитал доки к QSQLTableModel. Так там есть editStrategy (OnFieldChange, OnRowChange, OnManualSubmit), которая определяет, когда сабмитить изменения в базу. OnRowChanged отлавливается при попытке установить данные не текущей редактируемой строки или вставить новую строку. Кстати для OnFieldChange и OnRowChange вставка более одной строки запрещена. Имхо, для вашего случая надо что-то подобное. Возможно, было бы полезно сделать некий наследник QAbstractTableModel, который бы поддерживал понятие "текущая редактируемая строка". Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: Eugene Efremov от Май 03, 2009, 17:44 Eugene Efremov попытался написать своё негативное отношение к реализации model-view в Qt, а это не больно-то связано с названием статьи. Ммм... Я правильно понял, что основную негативную реакцию вызвали мои «лирические отступления», в которых я сетую на несовершенство реализации MVC в Qt? в начале статьи ссылка на меня и на наш диалог, хотя, в статье используются лишь собственные домыслы, а полуается, что и я причастен к этому... Ну вообще-то, без этого диалога статьи бы не было. Я получил из него довольно много информации, которую здесь и использовал, за что тебе отдельное спасибо. К сожалению, информации все-таки не хватило и кое-что пришлось домысливать. А дальше — уж что получилось, то получилось. Если бы мы продолжали тот диалог в прежнем режиме до полного прояснения всех деталей — возможно, результат был бы лучше. Но тебе это надоело. И это понятно, потому что способ это медленный и неэффективный. Я предложил, как альтернативу диалогу, вариант с написанием статьи, отражающим — со всеми его ошибками — мой текущий уровень, с последующим исправлением этих ошибок. Ты не возражал. Я написал. Естественно, многое описал неправильно, но ведь так и предполагалось с самого начала. Так чего же теперь зазря возмущаться наличием ошибок там, где они и должны быть по условиям задачи? Их исправлять надо... Цитировать Для чего тогда нужны QAbstractItemModel::createIndex принимающий целые числа или указатели, а также QModelIndex::internalPointer и QModelIndex::internalId их возвращающие? мб стоило сначала прояснить это для себя?До сих про я полагал, что они используются для сохранения в индексах — в той или иной форме — ссылок на элементы данных модели. Что-то не так? где используется createIndex(...)? Главным образом — в реализации метода index, насколько я понимаю. Цитировать Цитировать что не так с ролями Они реализованы через enum и тянут за собой повторяющийся switch/case во все места, где используются.Первое что приходит в голову — Factory(в той или иной форме) + State. Модель отвечает за предоставление фабрики, фабрика генерит иерархию состояний (читай тех же ролей, но объектно-ориентированных), через их методы View узнает о тех или иных аспектах модели. Кстати, если этот вариант обработать напильником, он и в текущую реализацию влезет, но придется все делать внутри модели, что весьма криво. Но сколько-нибудь оправдано это будет, лишь если эта модель сама лежит в корне большой иерархии других моделей... Другой вариант. Замечаем, что роли — это, по-существу, свойства элементов модели, и пляшем уже от этого. Это, пожалуй, лучше, чем вариант с фабрикой состояний, но потребует куда более существенной переработки всей системы. Цитировать Цитировать и с каких пор подсказки вьюхе считаются нонсенсом?; Смешение данных и представления.Для начала, встречный вопрос: а если я в одной вьюшке хочу выделять эти файлы синим, в другой — красным, а в третьей — вообще отмечать звездочкой? А теперь — ответ на все сразу. Модель не должна заморачиваться на тему «каким цветом выделить файл». Вьюха не должна заморачиваться на тему «а не архивный ли файл соответствует этому элементу». Более того, ей вообще совсем не обязательно знать, что такое файл. Единственное, что должна знать вьюшка — это что у данного элемента модели выставлен некий атрибут, и что элементы с таким атрибутом надо отображать неким особым способом. А будет она его выделять синим, красным или серо-буро-малиновым — это уже ее, вьюшки, личное дело. Дело же модели — этот атрибут выставить. И только. А не пытаться указывать вьюшке, как ей делать ее работу. С рисунками ситуация немного сложнее, поскольку, в зависимости от контекста, рисунок можно считать как частью данных, так и элементом представления. В данном случае иконки и превьюшки являются частью файла (или связанной с файлом метаинформацией), так что будет правильным считать, что мы имеем дело с первым вариантом. Соответственно, модель должна их обработать и предоставить вьюшке, попутно известив ее, если один из элементов отсутствует. Остальное — опять-таки не ее дело. далее: ты сетуешь на то, что в модель нельзя вставить поизвольный объём данных "одним махом". Хде?! (Посмотрев текст) Ты, что ли, имеешь в виду это: Цитировать Метод insertRows <...> не предоставляет средств для добавления в модель новых данных. Т.е., если мы хотим использовать для добавления новых элементов стандартный механизм — мы должны с помощью insertRows создать новую строку, и только затем уже — добавлять туда данные, вызывая setData для каждой ячейки. Это, кончено, очень неудобно, и мы еще вернемся к этому вопросу. Мда. Действительно, можно, наверное, и так понять. Надо будет как-то это переформулировать или дополнить. давай прикинем - абстрактная модель знать не знает сколько ты (разработчик) собираешься сделать столбцов в строке, <...> я всё-равно не могу предусмотреть эффективного интерфейса для данной задачи. но если могу, то почему просто его не добавить, как это сделано в QSqlTableModel (bool QSqlTableModel::insertRecord ( int row, const QSqlRecord & record ))? О, кстати. Это надо будет вставить в статью в качестве объяснения необходимости введения расширенного интерфейса. Пожалуй, если оно там будет, то предыдущий отрывок менять и не нужно... ах, вьюха не знает никакого insertRecord() модели. а разве вьюха добавляет/удаляет строки в/из модель/и?! Это делает контроллер. Которого у нас нет и который приходится писать ручками. Именно с использованием расширенного интерфейса. Если бы ты дочитал статью до конца, то увидел бы, что там про это написано. короче, каждое лирическое отступление в статье - это иллюстрация непонимания того или иного момента. Если и так, то что же? Я, кончено, могу их все удалить. И с теми, где пишется про case/switch и роли, наверное, так сделать лучше всего: тема слишком необъятна, вызывает очень много вопросов и выходит далеко за рамки статьи. Но в основной целью этих лирических отступлений является разъяснение, почему я использовал тот или иной способ решения задачи. То, что в результате получилась критика — возможно, необоснованная — в определенной мере закономерно: задачу всегда хочется решить наиболее красивым способом, а если инструмент этого не позволяет, то в первую очередь напрашиваться вывод, что инструмент плох. Хотя ограничения, конечно, могут быть и вполне объективными. Думаю, лучшим решением будет не удалять их, а исправить: если критика действительно вызвана непониманием, и в основе тех или иных ограничений имеются объективные причины — нужно указать эти причины и/или разъяснить ошибочность подобной «наивной» критики. нужно документацию внимательно читать, если чего-то не понимаешь. К сожалению, этого недостаточно. Документация хороша, когда ты уже понимаешь, что именно ты хочешь там найти. Того общего описания (http://www.doc.crossplatform.ru/qt/4.4.3/model-view-programming.html), которое там имеется, для этого понимания мало. Бланшета и Шлее — тоже. Если эту статью удаться довести до ума — может быть она хоть частично заткнет этот пробел... P.S. Между тем, прошло уже двое суток, а я так и не вижу ни одного указания на какую-либо конкретную ошибку. Все ограничивается критикой моей критики ;) У меня уже появляется крамольная мысль, что может все и не так плохо, может там вовсе даже и нет никаких по-настоящему серьезных ошибок, раз никто до сих пор меня в них пальцем ни ткнул? ;) P.P.S. Хотя на самом деле ошибки там, кончено же, есть. Вот только что просматривал текст, наткнулся на такой перл: Код :) Прямая иллюстрация пагубности копипасты, кстати. Надо будет не забыть поправить. Неужели никто этого не заметил? Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: Eugene Efremov от Май 03, 2009, 18:16 1. Вы пытаетесь обеспечить вставку произвольного числа строк. Я так и не понял - зачем? Ну разрешайте вставку тока одной, если идет попытка вставить больше - возвращайте false. Где? Никакой вставки произвольного числа строк за раз у меня нет. Кроме, конечно, требуемого интерфейсом insertRows. Так с ним — это не ко мне, это к троллям... 2. "Иными словами для beginInsertRows/endInsertRows совершенно безразлично, куда на самом деле вставляются новые столбцы — лишь бы их было нужное количество." - мне представляется, что подписчики этих сигналов используют информацию о месте вставки чтобы избежать ненужных запросов данных - им потребуется перерисовать тока вставленные столбцы. Если передавать неверную инфу - будут грабли с отрисовкой. Мне тоже это кажется странным. И хорошо бы, чтобы этот момент пояснил кто-нибудь из более знающих людей. Но факт остается фактом: это работает. Кстати, это один из моментов моей переписки с Константином, когда он выразился абсолютно четко и ясно и даже привел фрагмент кода. Но добиться у него объяснения, почему это работает, мне так и не удалось. 3. "Одним из требованием к модели была возможность полного доступа к ней с использованием только стандартного интерфейса QAbstractItemModel" - я не понял, почему мы должны использовать интерфейс QAbstractItemModel в реализации метода нашего же класса? Какие выгоды мы от этого получаем - код же просто кошмарный... :) Только чтобы убедиться, что этот интерфейс работает. А значит сущности, которые про нашу модель ничего не знают, могут им пользоваться. Сами мы, конечно, не обязаны это все использовать, если точно знаем, что перед нами именно наша модель и мы можем пользоваться ее расширенным интерфейсом. Можно считать это таким своеобразным юнит-тестом: сделать реализации через оба интерфейса и убедиться, что они работают одинаково. Цитировать Несомненно, читатель уже обратил внимание на уродливую связку swicth/case. Ну тут еще вопрос - что лучше. Если избавиться от role, то получится куча функций вида: data(), icon(), background(), tooltip(), whatWhis(), ... Про то, что можно было бы (если бы да кабы...) с этим сделать я уже отписал в письме Константину. А вообще — вижу что тема swicth/case/role вызывает много вопросов общего характера, которые к статье это имеют мало отношения. Так что, пожалуй ее упоминание из статьи лучше действительно убрать. А дискуссию на эту тему перенести в отдельную ветку... Цитировать Во-первых, вся система явно ориентирована на отдельную обработку каждой ячейки данных. И, соответственно, довольно криво работает в ситуациях, когда элемент занимает больше одной ячейки (а он, как правило, занимает целую строку). Я ради интереса почитал доки к QSQLTableModel. Так там есть editStrategy (OnFieldChange, OnRowChange, OnManualSubmit), которая определяет, когда сабмитить изменения в базу. OnRowChanged отлавливается при попытке установить данные не текущей редактируемой строки или вставить новую строку. Кстати для OnFieldChange и OnRowChange вставка более одной строки запрещена. Имхо, для вашего случая надо что-то подобное. Возможно, было бы полезно сделать некий наследник QAbstractTableModel, который бы поддерживал понятие "текущая редактируемая строка". Угу, вот только у нас, помимо QAbstractTableModel, есть уже готовый ворох ее наследников. И если мы хотим дополнить ее интерфейс для всех случаев — встает проблема, что делать с ними со всеми... Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: Eugene Efremov от Май 03, 2009, 18:44 Удалил из статьи вот это вот:
Цитировать Лирическое отступление №2 Несомненно, читатель уже обратил внимание на уродливую связку swicth/case. Более того, заглянув в исходный код примера, он мог бы обнаружить ту же самую связку в ф-циях headerData и setData. И у него должен был возникнуть закономерный вопрос — почему мы от нее не избавимся? К сожалению, это сделать не так-то легко. Полноценное решение включало бы в себя достаточно глубокую переработку всей имеющейся реализации MVC с избавлением от использования перечислений там, где следует использовать полиморфизм. По понятным причинам, мы этого сделать не можем. Обходные пути существуют, но они достаточно сложны. И их обсуждение выходит далеко за рамки данной статьи. Лирическое отступление №3 Я уж молчу о том, что многим из этих «ролей» вообще нечего делать в модели, поскольку с их помощью выясняются вопросы, находящиеся сугубо в компетенции представления. Ну какое, спрашивается, имеет отношение к модели цвет фона, размер шрифта и другие подобные вещи?! Дальнейшее обсуждение этой тематики (если есть желание) предлагаю перенести в отдельную тему (в разделе MVC). Здесь же, думаю, это нужно объявить оффтопиком. P.S. Также я подредактировал «лирическое отступление» к четвертой и добавил новое — к третьей. Теперь там объясняется, почему insertRows не добавляет в модель данные. Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: johnny от Май 03, 2009, 19:44 1. Вы пытаетесь обеспечить вставку произвольного числа строк... Где? Никакой вставки произвольного числа строк за раз у меня нет. Кроме, конечно, требуемого интерфейсом insertRows. Дык кто ж мешает, если count > 1 просто возвращать false? Зачем "натягивать" вставку многих записей, если это совершенно не нужно для нашей модели? Именно такое поведение у QSQLTableModel при некоторых настройках... Цитировать Возможно, было бы полезно сделать некий наследник QAbstractTableModel, который бы поддерживал понятие "текущая редактируемая строка". Угу, вот только у нас, помимо QAbstractTableModel, есть уже готовый ворох ее наследников. И если мы хотим дополнить ее интерфейс для всех случаев — встает проблема, что делать с ними со всеми... Ну на самом деле ни такой уж и ворох - QAbstractListModel (для которой это малоактуально), QAbstractTableModel и QStandartItemModel. Если неохота писать двух наследников - можно извернуться с шаблонным классом, предок которого определяется аргументом шаблона :) Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: ритт от Май 03, 2009, 21:23 умора :) нет, я должен был бросить всё и расжёвывать всё до полного понимания?)
ой, как было бы хорошо с контроллером...ну, нет контроллера, контроллера нет. так что же теперь? "босс, мы все умрём! даже ты, босс!" Цитировать Ммм... Я правильно понял, что основную негативную реакцию вызвали мои «лирические отступления», в которых я сетую на несовершенство реализации MVC в Qt? нет. я в среднем в месяц нахожу по баге-две и давно бросил их считать - одни банальны и легко исправляются, иные могут потребовать изменения интерфейса и до начала работ над 5.0 о них даже сообщать бессмысленно. из-за некоторых из них пару занимательных проектов мне пришлось приостановить как минимум до смены модели контрибуций. но по теории ошибки это всё неизбежно. я сообщаю о проблемах, пишу патчи - посильно пытаюсь улучшить инструмент. и все эти неудобства, с которыми мне пришлось столкнуться за время работы с Qt, даже не побудили меня отказаться от неё в пользу какого-нибудь точканета или жавы (или, тьфу-тьфу, гтк).для тебя, внимательный читатель, это всего лишь букавки :) а для меня это показатель. да хотя бы просто сравнить Qt3 с Qt4... хрен с ней со статьёй, к чертям отступления, лажай кого вздумается - мне по большому счёту всё это неинтересно. а тебе...ну, может, настроение улучшится или ещё чего?) хотя, с другой стороны, Цитировать Про то, что можно было бы (если бы да кабы...) с этим сделать я уже отписал в письме Константину. я заглянул в ПМ, заглянул в почту - письма от тебя не нашёл ни здесь, ни там. если отправлял что-то мне на мыльник, то я или напрочь этого не помню, или не получал.Цитировать Кстати, это один из моментов моей переписки с Константином, когда он выразился абсолютно четко и ясно и даже привел фрагмент кода. Но добиться у него объяснения, почему это работает, мне так и не удалось. вернулся к оригинальному треду и нашёл единственный сниппет, который я выкладывал:Код: void MyModel::insertMyRow(const QString& key, const MyData& data) право же, у меня фантазии не хватает понять как из этого...ммм...кода были сделаны выводы...которые были сделаны) Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: Eugene Efremov от Май 03, 2009, 23:00 Цитировать Ммм... Я правильно понял, что основную негативную реакцию вызвали мои «лирические отступления», в которых я сетую на несовершенство реализации MVC в Qt? нет. я в среднем в месяц нахожу по баге-две и давно бросил их считать - одни банальны и легко исправляются, иные могут потребовать изменения интерфейса и до начала работ над 5.0 о них даже сообщать бессмысленно. из-за некоторых из них пару занимательных проектов мне пришлось приостановить как минимум до смены модели контрибуций. но по теории ошибки это всё неизбежно. я сообщаю о проблемах, пишу патчи - посильно пытаюсь улучшить инструмент. и все эти неудобства, с которыми мне пришлось столкнуться за время работы с Qt, даже не побудили меня отказаться от неё в пользу какого-нибудь точканета или жавы Не понял, к чему это все? Да, из существующих на сегодня инструментов Qt — лучше, что мы имеем. И что? Код: void MyModel::insertMyRow(const QString& key, const MyData& data) право же, у меня фантазии не хватает понять как из этого...ммм...кода были сделаны выводы...которые были сделаны) Выводы были сделаны очень простые: 1. beginInsertRows/endInsertRows можно и нужно использовать за пределами insertRows — при реализации собственных методов вставки данных. 2. Поскольку в этом фрагменте мы вставляем данные в хэш — мы не можем контролировать, куда именно они вставятся. Следовательно, если этот код верен, то мы можем вставлять данные куда заходим, а не только в тот диапазон, который мы задали в beginInsertRows. Последний вывод меня сильно удивил. И я специально тебя переспросил по этому поводу — так ли это и не надо нам в этом случае делать что-то еще? Ответа на свой вопрос я не получил (кстати, я не получил его и сейчас). Провел эксперимент, который прошел успешно. Все что надо добавилось в модель, никаких глюков или сообщений в консоли замечено не было. После этого я счел наиболее разумным принять как рабочую гипотезу справедливость этого вывода, рассчитывая, что если это не так — после написания статьи меня поправят. Пока эти надежды остаются тщетными, увы... Цитировать Про то, что можно было бы (если бы да кабы...) с этим сделать я уже отписал в письме Константину. я заглянул в ПМ, заглянул в почту - письма от тебя не нашёл ни здесь, ни там. если отправлял что-то мне на мыльник, то я или напрочь этого не помню, или не получал.Какой e-mail, какое ПМ? :o Письмо в этом треде имеется в виду. Вот это (http://www.prog.org.ru/index.php?topic=9376.msg53533#msg53533). Знаешь, чем больше я с тобой переписываюсь, тем больше у меня складывается впечатление, что мы говорим на разных языках. И понимаем друг друга хорошо если наполовину. Постоянно выясняется, что под одними и теми же словами мы имеем в виду совершенно разные вещи. И делаем из этих слов совершенно не те выводы, на которые рассчитывал собеседник. Что с этим делать, я не знаю. Но, по крайней мере, нужно учитывать, что наиболее вероятной причиной любых возможных разногласий скорее всего является элементарное взаимонепонимание. Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: Eugene Efremov от Май 03, 2009, 23:33 Где? Никакой вставки произвольного числа строк за раз у меня нет. Кроме, конечно, требуемого интерфейсом insertRows. Дык кто ж мешает, если count > 1 просто возвращать false? Зачем "натягивать" вставку многих записей, если это совершенно не нужно для нашей модели? Именно такое поведение у QSQLTableModel при некоторых настройках...Можно конечно. Но мне не кажется, что это сколько-нибудь существенно повлияет на всю эту систему... Возможно, было бы полезно сделать некий наследник QAbstractTableModel, который бы поддерживал понятие "текущая редактируемая строка". Угу, вот только у нас, помимо QAbstractTableModel, есть уже готовый ворох ее наследников. И если мы хотим дополнить ее интерфейс для всех случаев — встает проблема, что делать с ними со всеми...Прямой предок нельзя, MOC с шаблонами не дружит. Можно заюзать множественное наследование и во втором классе через шаблон реализовать миксин. Но выглядеть будет довольно криво. Так что, если такие правки делать (а там, в принципе, еще много чего можно добавить), то лучше, IMHO, под конкретную модель конкретного проекта, которая уже сама должна встать в корне иерархии моделей этого проекта. Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: ритт от Май 04, 2009, 07:59 Цитировать Какой e-mail, какое ПМ? Письмо в этом треде имеется в виду. Вот это. мы действительно по-разному понимаем одни и те же слова. в моём языке "письмо" - это "письмо". бумажное, электронное...хотя бы записка на десктопе...хотя бы клинопись )Цитировать Выводы были сделаны очень простые: неверные выводы. если я ввёл в заблуждение фразой "я использую такую-то конструкцию для заполнения модели из кэша", ну, прости. опять же непонимание диалектов. я не вижу здесь "четкого и ясного" пояснения, что, мол, один хрен куда вставлять данные. в бэкинсторе может и один хрен, а подписчикам нужно сигналить правильно, если хочешь правильной работы.1. beginInsertRows/endInsertRows можно и нужно использовать за пределами insertRows — при реализации собственных методов вставки данных. 2. Поскольку в этом фрагменте мы вставляем данные в хэш — мы не можем контролировать, куда именно они вставятся. Следовательно, если этот код верен, то мы можем вставлять данные куда заходим, а не только в тот диапазон, который мы задали в beginInsertRows. если помнишь, я предлагал написать простенькую item-based модель и работать с ней. а, ещё - индексы не используются для хранения данных, индексы указывают на данныне. не прямо-таки указывают "данные здесь", а позволяют оперировать с данными по некому указанию позиции в модели. если ты повесишь вьюхе проксимодель, возьмёшь индекс интересующей ячейки и запомнишь его, затем пересортируешь прокси (заметь, модель-источник не меняется) и попробуешь работать с данными по сохранённому индексу, что у тебя получится? попробуй. в таком случае как же выделение ячеек не сбрасывается при сортировке прокси и почему оно даже продолжает работать? читай QPersistentModelIndex. Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: ритт от Май 04, 2009, 11:21 кстати, вот:
Цитировать void QAbstractItemModel::rowsInserted ( const QModelIndex & parent, int start, int end ) [signal] чётко и ясно - есть старт, есть энд для определённого парентаThis signal is emitted after rows have been inserted into the model. The new items are those between start and end inclusive, under the given parent item. Note: Components connected to this signal use it to adapt to changes in the model's dimensions. It can only be emitted by the QAbstractItemModel implementation, and cannot be explicitly emitted in subclass code. See also insertRows() and beginInsertRows(). Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: xintrea от Май 09, 2009, 15:13 С интересом почитал тред. Узнал, что в Qt недовольны реализацией MVC.
Каг считают гуру, означает ли это что в Qt 5.0 логика MVC в Qt будет переработана? Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: ритт от Май 09, 2009, 17:38 кривить душой не буду - на эту тему с троллями не общался. но думаю, улучшения будут...недаром же IV-NG разрабатываются (конечно, можно предположить, что это забавы ради...но не хочется)
Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: pastor от Май 09, 2009, 19:08 Каг считают гуру, означает ли это что в Qt 5.0 логика MVC в Qt будет переработана? Очень даже возможно Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: Eugene Efremov от Май 11, 2009, 18:52 Цитировать Какой e-mail, какое ПМ? Письмо в этом треде имеется в виду. Вот это. мы действительно по-разному понимаем одни и те же слова. в моём языке "письмо" - это "письмо". бумажное, электронное...хотя бы записка на десктопе...хотя бы клинопись )О том и речь. Для меня сообщение в треде на форуме — тоже вполне себе письмо... И раз у нас возможны такие непонятки — предлагаю сосредоточиться в первую очередь на исходном коде. Уж на C++, в отличии от русского языка, неоднозначная трактовка маловероятна... Цитировать 2. Поскольку в этом фрагменте мы вставляем данные в хэш — мы не можем контролировать, куда именно они вставятся. Следовательно, если этот код верен, то мы можем вставлять данные куда заходим, а не только в тот диапазон, который мы задали в beginInsertRows. неверные выводы. если я ввёл в заблуждение фразой "я использую такую-то конструкцию для заполнения модели из кэша", ну, прости. опять же непонимание диалектов. я не вижу здесь "четкого и ясного" пояснения, что, мол, один хрен куда вставлять данные. в бэкинсторе может и один хрен, а подписчикам нужно сигналить правильно, если хочешь правильной работы.Но тогда, опять-таки, встает вопрос, что делать в описанной ситуации. Вот у нас данные, мы их хотим вставить в хэш. Что нам передавать beginInsertRows? Сейчас туда пишется нечто мало осмысленное. Можно, конечно, сперва вставить пустые строки в конец модели, а потом вызвать insertToEmpty. А insertToHash вообще выкинуть. Но уж больно криво получается... если помнишь, я предлагал написать простенькую item-based модель и работать с ней. Угу. И именно это я и попытался сделать. Получилось... то что получилось. И собственно, именно на этом коде я и предлагаю сосредоточиться. Какие ошибки ты видишь в нём? Одну ошибку уже и сам могу назвать — это то самое неправильное использование beginInsertRows. Но способа ее исправить я пока не вижу. /* Код находится в приложении к первому сообщению в теме. Пока что, оно скачано 0 раз. */ а, ещё - индексы не используются для хранения данных, индексы указывают на данныне. не прямо-таки указывают "данные здесь", а позволяют оперировать с данными по некому указанию позиции в модели. Похоже — опять разница в языках. Для меня «указывают на» и «хранят указатель/ссылку/etc на» по смыслу суть синонимы... И речь в том отступлении шла о том, в качестве такой ссылки можно было бы использовать ключ от хэша, но реализация этого не позволяет, а потому мы этот механизм не используем. (И, кстати, целью оного отступления было именно объяснить, почему этот механизм в модели не используется. А вовсе не «наезды на троллей» или что-то еще в таком духе.) если ты повесишь вьюхе проксимодель, возьмёшь индекс интересующей ячейки и запомнишь его, затем пересортируешь прокси (заметь, модель-источник не меняется) и попробуешь работать с данными по сохранённому индексу, что у тебя получится? Полагаю, там будет указатель на данные, которые теперь находятся уже совсем по другим координатам... Соответственно — чушь получится... Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: ритт от Май 11, 2009, 20:32 Цитировать Но тогда, опять-таки, встает вопрос, что делать в описанной ситуации. Вот у нас данные, мы их хотим вставить в хэш. Что нам передавать beginInsertRows? не нужно никаких пустых строк. чего ты к ним привязался? )Сейчас туда пишется нечто мало осмысленное. Можно, конечно, сперва вставить пустые строки в конец модели, а потом вызвать insertToEmpty. А insertToHash вообще выкинуть. Но уж больно криво получается... добавь метод, принимающий список...чего там у тебя? строки? в общем, список "строк", где каждая "строка" - данные для строки модели. зови beginInsertRows(...) для вставки нужного количества строк, например, в конец списка (неважно куда - важно соблюдать заданную последовательность). между beginInsertRows(...)/endInsertRows() вставляй свои строки в хэш. для соблюдения последовательности тебе нужно завести вектор индексов и растягивать/сжимать его при добавлении/удалении строк. здесь ограничение - такая модель сможет работать только с уникальным набором ключей (что тебе, собственно, и требовалось). вопросы? Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: Eugene Efremov от Май 13, 2009, 18:45 для соблюдения последовательности тебе нужно завести вектор индексов и растягивать/сжимать его при добавлении/удалении строк. здесь ограничение - такая модель сможет работать только с уникальным набором ключей Мда. В переводе на русский язык это значит, что заставить эту систему нормально работать с действительно неупорядоченными данными невозможно. Я этого способа изо всех сил старался избежать. Вот цитата из статьи: Для ускорения доступа мы могли бы сохранять ключи в отдельном массиве и обращаться к его индексам. И в реальности, скорее всего, так бы и поступили. Но это лишило бы ценности наш пример, поскольку данные перестали бы быть неупорядоченными. Однако, судя по всему, именно так и придется сделать. Альтернативы слишком уж кривыми получаются. вопросы? Вопрос один, и чисто риторический. Как же с этим справляются модели, работающие с файловыми системами, базами данных и т.д.? Они что, тоже заводят промежуточные массивы для сохранения порядка индексов? (посмотрев код QFileSystemModel) Мда. Похоже, именно это они и делают. Все, больше вопросов нет. Видно, придется переписывать все заново под этот вариант... Название: Re: HowTo: Модель для неупорядоченных данных Отправлено: ритт от Май 13, 2009, 21:14 с этим всё просто - во вьюхе данные отображаются в определённом порядке или как-попало? если бы "как-попало", модели были бы не нужны )
|