Как стать автором
Обновить

Комментарии 11

Вы бы кодом показали, что именно у вас не работало. На словах выглядит так, что вы просто неправильно реализовали (или забыли перегрузить) метод buddy в прокси модели. Но ведь в документации достаточно прозначно написано то, что вы расписали на целую статью.

Я сам недавно с ним накосячил - возвращал индекс исходной (source) модели, но это очень легко нашёл и сразу исправил.

Вы правы - я забыл перегрузить метод buddy (впрочем о этом я написал), вы правы что об этом написано в документации, но, к сожалению, не в самом очевидном месте - но тут тоже я написал, что надо внимательнее читать документацию.

А в статье я хотел показать насколько я был фрустрирован данной ситуацией.

Код там довольно прямолинейный (на питоне):

    def buddy(self, index: QModelIndex) -> QModelIndex:
        if index.isValid() and index.model() == self:
            return index

        return super().buddy(index)

Вообще для прокси модели правильно сделать так (псевдокод). Проверки на валидность индекса избыточны.

sourceIndex = mapToSouce(index)
sourceBuddy = soureModel.buddy(sourceIndex)
return mapFromSource(sourceBuddy)

Да, вы все правильно пишите, и базовая реализация QAbstractProxyModel именно так и делает. Это работает, пока нам требуется редактировать только те индексы, которые существуют в исходной модели.

Но проблема в том, что в моем случае (я об этом как раз написал в статье) у меня в прокси-модели существуют индексы, которые в исходной модели отсутствуют. Очевидно, что для таких индексов, что mapToSource, что mapFromSource вернут не валидный индекс. И, соответственно, редактирование работать не будет. Поэтому я проверяю, что если индекс принадлежит прокси-модели, то возвращаю этот индекс в качестве buddy.

Ну то есть сверху есть ещё слой бизнес логики который вы не привели. Увы, я всё таки не понял о чём статья, кроме того что надо читать и быть внимательным при разработке прокси моделей. Что и так очевидно.

Или, другой пример, вам необходимо реализовать группировку объектов на основе атрибутов или дать возможность пользователю произвольно группировать объекты исходного дерева. В этих случаях вам придется реализовать свою прокси-модель на основе QAbstractProxyModel.

Как ее правильно реализовать - об этом можно поговорить отдельно. Сегодня я хотел рассказать про ошибку, с которой вы можете столкнуться, если будете реализовывать прокси-модель из последнего примера:

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

У вас, судя по комментариям, есть достаточный опыт, чтобы понять, что базовых возможностей для решения данной задачи не достаточно и необходимо делать свою реализацию прокси-модели. При условии, что у нас исходная модель, которую мы менять не можем (поэтому и заморачиваемся с прокси-моделью).

Если какие-то формулировки в статье не понятны - давайте их конструктивно обсуждать, чтобы сделать статью лучше.

Кода не хватает. Да, опыт с очень разными моделями, в том числе многопоточными, примерно 10 лет.

К примеру, очень часто вижу общую ошибку, что при переопределении метода index все всегда стараются возвращать только существующий индекс, но это неправильно. Для несуществующих элементов тоже надо возвращать index с корректной строкой или столбцом но пустым указателем, иначе при использовании прокси моделей которые меняют количество и порядок столбцов будут проблемы. И такие индексы надо правильно обрабатывать во всех методах.

У меня опыта с Qt будет меньше. Добавить щепотку многопоточности в прокси-дерево в ближайших планах.

По несуществующим индексам - я может быть вас не понял, но в моей практике я сталкиваюсь с невозможностью вносить изменения в исходную модель и приходится делать все в прокси-модели, в том числе и индексы для несуществующих элементов. Ну и там хочешь, не хочешь, но их обрабатывать надо правильно, т.к. если сходить в internalPointer чужого индекса, да если там еще и данных нет, то будет довольно больно.

По поводу кода - у меня были опасения, что за деревьями не будет видно леса. Т.к. объективно, чтобы продемонстрировать данную проблему, надо написать две модели и еще вью добавить, в которой, например, реализовать пользовательский интерфейс для группировки элементов.

В планах есть написать туториал, но это гораздо больше работы, чем небольшая заметка о конкретной проблеме.

С другой стороны с удовольствием послушал бы про ваш опыт.

Вам просто достаточно осознать что в Qt MVC модель не является хранилищем данных. На самом деле это лишь адаптер для бизнес логики. И если вам надо линейную модель разбить на группы, то не нужно это делать через прокси модели. Это намного проще сделать на уровень ниже.

А по поводу internalPointer - тоже до штука интересная. К примеру в стандартной модели это указатель на парент ноду (внезапно), а не на текущую. Это здорово оптимизирует производительность работы с persistent индексами, когда пишутся обработчики layoutChanged и многие другие вещи.

К сожалению, как я говорил выше, я не могу вносить изменения в исходную модель. Слишком много связанных трудозатрат получается.

А по поводу internalPointer - интересная информация, спасибо, надо будет изучить вопрос.

Ценность таких статей, я считаю, даже не в том, что это очередное, казалось бы, очевидное предупреждение из разряда "мойте руки перед едой", "будьте осторожны, работая с прокси-моделями" или "внимательнее читайте документацию". Ценность в том, что такие статьи должны (будут теперь) гуглиться по фразе "edit: editing failed" и спасать отчаявшихся :)

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории