Эффективное обновление QTableView на высокой скорости - PullRequest
8 голосов
/ 22 сентября 2010

Я использую QTableView с подклассом QItemDelegate для управления внешним видом ячеек таблицы.

Каждая ячейка отображает имя и статус устройства, подключенного извне, и столько, сколькоОдновременно может быть подключено 100 устройств.

Имя и тип каждого устройства в основном статичны, обновляются очень редко (возможно, раз в час), но каждая ячейка должна отображать значение в реальном времени входа устройства,который я в настоящее время опрашиваю каждые 50 миллисекунд.Это значение отображается в виде базовой гистограммы, нарисованной художником, предоставленным методу Delegate :: paint () в TableView.

Проблема с обновлением моей модели 20 раз в секунду заключается в том, что вся таблица перерисовываетсякаждый раз, что крайне неэффективно.Ограничение метода рисования только до рисования гистограммы показывает, что большая часть процессорного времени отводится для рисования имени, статуса и связанного изображения в каждой ячейке, а не на графике.

Что мне нужно найти, так этоспособ регулярно обновлять график для каждой ячейки, не перерисовывая ячейку, но я не могу понять, как это сделать.

Какой самый эффективный способ добиться этого?

Редактировать: Изображение, прикрепленное к справке.

Изображение представляет 10 датчиков в QTableView.Число, Имя и Статус практически статичны и почти никогда не обновляются.Гистограмма рядом с текстом «Значение датчика» обновляется каждые 50 мс.Я только хочу нарисовать эту строку, а не текст, статус и фон ячейки.Индикаторы состояния и фон являются сложными изображениями, поэтому занимают гораздо больше процессорного времени, чем простое рисование и заполнение прямоугольника.

alt text

Ответы [ 3 ]

6 голосов
/ 22 сентября 2010

, поскольку ваш QTableView наследует QWidget, вы можете вызвать на нем следующее:

setUpdatesEnabled(false);
changeAllYourData();
setUpdatesEnabled(true);

Когда setUpdatesEnabled имеет значение false, любой вызов paint () или update () для него не имеет никакого эффекта. Таким образом, вы можете остановить его обновление, изменить все ваши данные и затем снова включить его, возможно, вручную вызвав paint () или update () вручную, я не уверен в этой части.

Вот документация для метода setUpdatesEnabled.

Обновления QWidgetEnabled

Надеюсь, это поможет.

РЕДАКТИРОВАТЬ после комментария от пользователя:

Вы можете реализовать свой собственный setUpdatesEnabled (bool) для своего подкласса QItemDelegate (поскольку он не наследует QWidget и не имеет его), протестировав флаг перед выполнением вашего исходного paint () или update (). После этого вы можете указать для каждой ячейки (или строки, или столбца) вашего QTableView, должны ли они быть обновлены или перекрашены.

Сделав это, вы можете остановить перекрашивание других ваших ячеек (делегатов), если только вы не измените флаг setUpdatesEnabled, который вы создали вручную, но сохраните обновления в ваших ячейках, содержащих график.

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

Удачи

РЕДАКТИРОВАТЬ после редактирования пользователем:

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

Надеюсь, это поможет,

EDIT:

Я наткнулся на новую функцию в Qt 4.7 (я не знаю, возможно ли вам ее использовать, но она может решить некоторые ваши проблемы.) Особенностью является QStaticText. Это класс, который позволяет вам кэшировать текст (шрифт и эффекты) и рисовать их быстрее. Смотрите ссылку здесь .

Надеюсь, это решит вашу проблему.

2 голосов
/ 24 сентября 2010

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

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

1 голос
/ 22 сентября 2010

Кэшируйте фоновое изображение (фоновое изображение ячейки, статус и имя) в модель как QPixmap.Перерисовывайте это растровое изображение только при изменении статуса или имени.В общем случае вам нужно только нарисовать кэшированную QPixmap и значение датчика поверх этого.

Редактировать:

Добавить флаг fullRepaintNeeded в ваш класс данных.При изменении статуса или имени для fullRepaintNeeded устанавливается значение true.

Когда делегат рисует элемент, делегат сначала проверяет флаг элемента fullRepaintNeeded.Если fullRepaintNeeded - true, тогда создается новый QPixmap, и все отображается в этом QPixmap, который в конечном итоге отображается в табличном представлении.Затем QPixmap кэшируется в модель (что означает для вашего класса данных) с помощью функции setData модели (но dataChanged не вызывается).fullRepaintNeeded теперь имеет значение false.

Но если fullRepaintNeeded имеет значение false в функции рисования делегата, из модели запрашивается ранее кэшированное QPixmap, которое отображается в табличном виде, и поверх него выводится значение датчика finally.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...