LINUX.ORG.RU

QTableView не обновляет число видимых колонок при изменении в модели

 , , ,


0

3

Делаю я в своем проекте переход со связки

QTableView-QAbstractTableModel

на связку

QTableView-QSortFilterProxyModel-QAbstractTableModel

то есть, внедряю промежуточную прокси модель.

Проблема в том, что раньше, когда у меня был просто класс recordSourceModel (унаследованный от QAbstractTableModel), то при изменении числа видимых колонок в этой модели, вид сразу начинал отображать новые колонки. Для этого нужно было только «передернуть» модель, вот так:

  setModel(NULL);
  setModel(recordSourceModel);

Теперь, у меня есть класс recordProxyModel (унаследованный от QSortFilterProxyModel). Он сейчас практически пустой - есть только пустые конструктор и деструктор. По идее, он должен тупо ретранслировать все данные recordSourceModel, потому что ему задана эта модель через setSourceModel(recordSourceModel).

И recordProxyModel действительно ретранслирует все данные recordSourceModel. И измененное число колонок тоже.

Но вид не отображает новое число колонок при их изменении. Не помогает и «передергивание» модели:

  setModel(NULL);
  setModel(recordProxyModel);

Я даже откатился назад, перепроверил с recordSourceModel - изменение числа колонок отображается в виде. Но когда настраиваешь вид на recordProxyModel, то изменение числа колонок на вид никак не влияют.

Что делать, как исправить?

★★★★★

А разве не модель должна говорить об изменении колонок? begin(Insert/Remove)Columns.

panter_dsd ★★★★ ()

Для этого нужно было только «передернуть» модель, вот так:

  setModel(NULL);
  setModel(recordSourceModel);

Что за глупости? Когда в модель добавляются колонки, она должна вызывать beginInsertColumns/endInsertColumns, что в свою очередь генерирует сигналы columnsAboutToBeInserted/columnsInserted. Эти сигналы ловит QSortFilterProxyModel, выполняет фильтрацию/сортировку и при необходимости генерирует такие же сигналы, которые, в свою очередь, ловятся уже твоим QTableView. По этим сигналам view и узнает, что требуется добавить колонки. Предполагаю одно из двух: либо ты не вызываешь в исходной модели beginInsertColumns/endInsertColumns (если конечно ты используешь не стандартную модель), либо твоя прокси-модель просто фильтрует эти колонки.

m0rph ★★★★★ ()
Последнее исправление: m0rph (всего исправлений: 1)
Ответ на: комментарий от m0rph

Да, не вызываю...

У меня данные о видимых столбцах хранятся не в модели, а в конфигурации программы. Модель просто каждый раз в методе data() обращается к объекту конфигурации и узнает, какие данные ей нужно показывать в виде: сколько колонок, и в какой последовательности. Модель это делает и для заголовков, и для самих данных.

Конфигурация может в любой момент работы программы поменяться (пользователь изменил настройки). Причем, количество колонок может произвольно увеличиться или уменьшиться (от 1 до ~10), и последовательность колонок тоже может поменяться.

Конфигурация ничего не знает, что там показывает вид и модель. И не должна знать. Она считает, что вид всегда показывает то, что прописано в конфигурации. Единственное, что делает конфигурация - в случае изменения настроек отправляет виду сигнал, чтоб тот «перегрузил» модель (поставил в NULL, потом опять ту же модель). А модель при следующих вызовах data() просто выдает данные согласно конфигурации.

И раньше это работало. Почему же сейчас не работает?

Xintrea ★★★★★ ()
Ответ на: комментарий от Xintrea

Ты неправильно используешь Qt'шный model/view framework. Все, что у тебя получится - это временно работающее решение на основе кучи подпорок. Выйдет новая версия Qt, в которой разработчики случайно поломают поведение, на которое ты заложился (недокументированное, которое никто не гарантировал) и твоя программа порушится как карточный домик. Уже сейчас можно однозначно сказать, что при изменении данных твоим способом (методом «сброса» модели) будет теряться пользовательское выделение элементов и позиция прокрутки. Кроме того это достаточно тяжелая операция - замена модели. Если элементов у тебя там на пару экранов, разницу ты конечно не увидишь. Но будь там несколько тысяч строк или колонок, которые к тому же достаются из какой-нибудь БД - ты бы ощутил всю «прелесть» такого подхода.

m0rph ★★★★★ ()
Ответ на: комментарий от m0rph

Ну а как правильно делать, если нужно хранить назначение и количество столбцов в конфигурации, и конфгурация может произвольно эти данные менять?


По поводу структуры:

Во-первых, метод сброса модели работает и в Qt4 и в Qt5, прога и там и там живет нормально.

И второе - вид запрашивает у модели ровно столько элементов, сколько видно на экране. Так что сказки про нагрузку в несколько тыщ строк - это только сказки.

Xintrea ★★★★★ ()
Ответ на: комментарий от Xintrea

Ну а как правильно делать, если нужно хранить назначение и количество столбцов в конфигурации, и конфгурация может произвольно эти данные менять?

Нужно соблюдать протокол взаимодействия, т.е. при изменении данных в модели вызывать необходимые функции. Ты что, не знаешь когда твоя «конфигурация» изменяется и как она это делает? Добавляются новые колонки - вызывай beginInsertColumns/endInsertColumns, удаляются существующие колонки - вызывай beginRemoveColumns/endRemoveColumns, изменяются данные - генерируй сигнал dataChanged. Если полностью меняется расположение элементов (например при фильтрации/сортировке), там уже надо генерировать сигналы layoutAboutToBeChanged и layoutChanged, попутно обновляя существующие потстоянные индексы (QPersistentModelIndex).
Исходя из твоего описания, Qt'шная модель у тебя не модель данных, а фактически просто адаптер между реальными данными и вьюхой. Понимаю твое неудобство совмещать ужа с ежом, но ты же сам это затеял. Лично я предпочитаю использовать модель данных именно как модель данных. Нужно организовать хранение информации подходящим способом. Таким, чтобы и работать с данными было удобно, и с выдачей конкретного N-нного элемента не было трудностей. Если ты например хранишь информацию внутри в каком-нибудь set'е или map'е, придется как-то организовывать произвольный доступ к N-ному элементу. Даже если выбросить модели Qt и сделать свой велосипед, все равно придешь к тому же самому - необходимости случайного доступа к элементу для отображения во вьюхе.

m0rph ★★★★★ ()
Ответ на: комментарий от Xintrea

Ну а как правильно делать, если нужно хранить назначение и количество столбцов в конфигурации, и конфгурация может произвольно эти данные менять?


Подписываешься на событие обновления файла. Как только файл обновился - перечитываешь его и информируешь всех подписантов через стандартный интерфейс модели.

trex6 ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.