Как пересылать сигналы в модели-оболочке QAbstractItemModel

Я намерен создать свою собственную модель элемента, производную от QAbstractItemModel. Модель не содержит данных, но оборачивает некоторый репозиторий данных. Этот репозиторий излучает сигналы после того, как элементы вставлены, удалены, переименованы и т. д.

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

Однако репозиторий имеет автономные сигналы, такие как void itemRemoved(int index);, в то время как QAbstractItemModel имеет пары начала/конца защищенных функций (и сигналов), таких как beginInsertRows() и endInsertRows().

Как мне справиться с этим? Например. Я мог бы подключить слот, подобный следующему, к сигналу itemRemoved() репозитория:

void RepositoryItemRemoved(int i)
{
   beginInsertRows(QModelIndex(), i, i);
   endInsertRows();
}

На основе приведенного выше примера: допустимо ли вызывать beginInsertRows() / endInsertRows() последовательно после того, как строка была вставлена ​​в репозиторий?


person Silicomancer    schedule 04.04.2016    source источник
comment
Есть ли у вас какие-либо идеи, какие побочные эффекты могут возникнуть из-за несоблюдения предполагаемого использования?   -  person Silicomancer    schedule 05.04.2016
comment
Честно говоря, мне эта схема не очень понятна. Одного сигнала после вставки или удаления данных должно быть достаточно, чтобы выполнить эту работу. Это может быть проблематично только в многопоточном контексте, но тогда простой мьютекс поможет. Я мог что-то упустить, но у меня было много случаев, когда внутренности Qt спроектированы неоптимально.   -  person dtech    schedule 05.04.2016


Ответы (2)


У меня был похожий сценарий, когда данные находятся в другом объекте, а модель является просто оболочкой и создается только в том случае, если этот набор данных отображается в представлении. Я использовал указатель на объект модели в объекте данных, проверяя, является ли он нулевым при операциях вставки, и если нет, вызывайте через него beginInsertRows() и endInsertRows(). Естественно, поскольку они защищены, класс данных должен быть объявлен другом класса модели.

В документации подчеркивается, что важно вызывать beginInsertRows() перед вставкой каких-либо данных:

При повторной реализации insertRows() в подклассе вы должны вызвать эту функцию перед вставкой данных в базовое хранилище данных модели...

... В противном случае представления могут оказаться в недопустимом состоянии.

Вы должны протестировать представление или, альтернативно, изучить фактическую реализацию в исходном коде.

person dtech    schedule 04.04.2016

У меня тоже был несколько похожий сценарий, только в моем случае модель Qt обернула базовую модель немного более буквально: базовая модель содержала достаточно больше данных, чем представление должно было знать. Поэтому я позволил модели Qt содержать свой собственный список небольших фрагментов каждого элемента данных базовой модели, с которыми может иметь дело представление/делегат. Итак, слоты, обрабатывающие обновления базовой модели, выглядели так:

void RepositoryItemRemoved(int i)
{
    beginRemoveRows(QModelIndex(), i, i);
    removeModelItem(i);
    endRemoveRows();
}

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

person Dmitry    schedule 31.05.2016