Наличие модели Qt только для чтения и просмотра в разных потоках - PullRequest
0 голосов
/ 11 июня 2019

Как я узнал из документации Qt, в платформе Qt Model / View модели и связанные с ними представления должны находиться в одном потоке (GUI). Это может привести к нежелательным последствиям, таким как следующие. Я вложил в подкласс QAbstractTableModel и реализовал необходимые виртуальные функции. Внутри модель делает запросы в базу данных sqlite, которая имеет много записей, и предоставляет данные соответственно присоединенным представлениям через переопределенную функцию data().

Теперь в GUI у меня есть QTableView, который я прикрепил к этой модели. Также у меня есть QLineEdit поле ввода. При печати текста в этом поле генерируется сигнал textChanged(), который подключается к (пользовательскому) слоту query() модели. Таким образом, ввод нового символа в поле ввода должен обновить таблицу с записями, соответствующими набранной фразе.

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

Но меня беспокоит то, что, поскольку я обязан иметь модель и таблицу в одном и том же потоке графического интерфейса пользователя, поле ввода также исчезает после каждой буквы, пока таблица не обновится. Я хотел бы сделать так, чтобы я мог набрать фразу без эффекта замораживания и дождаться обновления таблицы. Уведомление модели только тогда, когда вся фраза набрана нажатием Enter, для меня не вариант - мне нужен сигнал textChanged().

Итак, я подумал - будет ли это большим оскорблением для Qt, если я проигнорирую документы и вставлю модель в поток без GUI? К моему удивлению, это сработало! Теперь набор текста не останавливается, и программа не падает (по крайней мере, пока).

Так что мой вопрос - тем не менее, небезопасно ли использовать модель в потоке без GUI, и моя программа может внезапно завершиться сбоем в любой другой день? Я также должен упомянуть, что я хочу использовать модель только для чтения. Если мне нужно изменить данные, лежащие в основе модели, я не буду делать это с использованием представления / делегатов, я просто отправлю соответствующие сигналы в поток модели, и все изменения будут выполнены в этом потоке.

1 Ответ

0 голосов
/ 11 июня 2019

Представьте себе этот пример удаления последней строки:

Синхронный (тот же поток)

  1. emit beginRemoveRows(int r = last row)
    • view реагирует и удаляет ссылки на r
  2. удалить r из модели
  3. endRemoveRows()
    • представление знает, что это может перекрасить

Асинхронный (разные потоки)

  1. emit beginRemoveRows(r)
  2. удалить r из модели
  3. endRemoveRows()

Оба сигнала находятся в очереди событий потока GUI.

Если очередь событий GUI содержит событие перерисовки до beginRemoveRows(), представление вызовет model->data(r) и ваша программа, скорее всего, вылетит *.

(*) Или, по крайней мере, столкнитесь с безопасностью вашей data() реализации, но под капотом есть и другие вещи, такие как QPersistentModelIndex, которые вы не контролируете ...

...