QProgressBar в таблице QTableView

QProgressBar в таблице QTableView

Виджет таблицы в Qt представляет собой довольный гибкий и удобный компонент для вывода структурированных данных. Используя QTableView вы можете полностью контролировать способ отображения данных модели. Одной из типичных задач является отрисовка в ячейке таблицы индикатора прогресса QProgressBar. Этим мы сейчас и займемся.

Подготовительный этап

Не будем усложнять демонстрационный пример и определим следующий простой виджет:

За основу мы взяли не сам QTableView, а его наследника QTableWidget, для которого не требуется создавать дополнительный класс модели. Однако все, о чем мы будем говорить, будет работать и для QTableView. Более того, описанный подход также будет работать для QTreeView и QListView.

На форме виджета мы разместим таблицу с единственным столбцом Progress. А внизу прикрепим кнопку Add. После нажатия на кнопку в таблицу будет добавлена строка и запустится таймер. Этим таймером мы будем моделировать некую активность и наращивать значение прогресса от нуля до сотни. Соответствующая реализация не намного сложнее, чем звучит ее описание:

Здесь лишь обратим внимание на то, что новая строка в таблицу добавляется с помощью insertRow(). После чего создается элемент QTableWidgetItem, который мы прикрепим к новой строке. Для него мы убираем возможность редактирования исключая флаг Qt::ItemIsEditable. Установка нового значения происходит в слоте onProgress() с помощью функции-члена setData() для роли Qt::DisplayRole.

Приложение уже можно запустить, и оно будет отображать возрастающий прогресс, но никакого специального индикатора вы не увидите. Это будет обычное текстовое поле с цифрами:

Но это не проблема. Сейчас мы легко все поправим.

Пишем ProgressBarDelegate

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

В функцию paint() нашему делегату будут переданы:

  1. Объект класса QPainter, которым мы и будем рисовать индикатор;
  2. Набор опций для отображения ячейки QStyleOptionViewItem;
  3. Индекс модели QModelIndex, с помощью которого мы можем получить всю необходимую информацию о ячейке таблицы, которую нам предстоит нарисовать.

А вот и реализация делегата:

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

В конце функции paint() мы сначала вызываем реализацию, предусмотренную в базовом классе, но передали в последнем аргументе пустой QModelIndex, чтобы не выводить никаких данных модели. Это нужно, чтобы наша ячейка могла отображать некоторые базовые состояния, типа рамки фокуса и подсветки в случае выбора (можете убрать эту строку и убедиться, что ничего не происходит, когда вы щелкаете по ячейкам). А сам индикатор прогресса с заготовленными параметрами рисуется вызовом QApplication::style()->drawControl().

Вот и все. Осталось заменить стандартный делегат в таблице на наш. Это нужно сделать в конструкторе виджета. В том месте, где мы создавали m_table. В результате должен получиться примерно такой фрагмент:

После запуска и пары нажатий на кнопку Add я получил следующее.

Все работает!

Заключение

Вот мы и познакомились со способом отображения индикатора прогресса в виджете таблицы. Таким же образом вы можете рисовать в своем делегате вообще все, что угодно. Кроме того, поскольку базовые классы у QTableView, QTreeView и QListView общие, то одни и те же делегаты будут работать в любом из них.

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