QProgressBar у таблиці QTableView - IT Notes
Віджет таблиці Qt являє собою задоволений гнучкий і зручний компонент для виведення структурованих даних. Використовуючи QTableView, ви можете повністю контролювати спосіб відображення даних моделі. Однією з типових завдань є відмальовування в осередку таблиці індикатора прогресу QProgressBar. Цим ми зараз і займемося.
Підготовчий етап
Не ускладнюватимемо демонстраційний приклад і визначимо наступний простий віджет:
За основу ми взяли не сам QTableView, а його спадкоємця QTableWidget, для якого не потрібно створювати додатковий клас моделі. Однак все, про що ми говоритимемо, буде працювати і для QTableView. Більш того, описаний підхід також працюватиме для QTreeView і QListView .
На формі віджету ми розмістимо таблицю з єдиним стовпцем Progress. А внизу прикріпимо кнопку Add. Після натискання на кнопку до таблиці буде додано рядок і запуститься таймер. Цим таймером ми моделюватимемо якусь активність і нарощуватимемо значення прогресу від нуля до сотні. Відповідна реалізація не набагато складніша, ніж звучить її опис:
Тут лише звернемо увагу на те, що новий рядок до таблиці додається за допомогою insertRow() . Після цього створюється елемент QTableWidgetItem , який ми прикріпимо до нового рядка. Для нього ми прибираємо можливість редагування за винятком прапора Qt::ItemIsEditable . Установка нового значення відбувається у слоті onProgress() з допомогою функції-члена setData() для ролі Qt::DisplayRole .
Програму вже можна запустити, і вона відображатиме зростаючий прогрес, але ніякого спеціального індикатора ви не побачите. Це буде звичайне текстове поле із цифрами:

Але це не проблема. Зараз ми легко все виправимо.
Пишемо ProgressBarDelegate
А для цього нам знадобиться не так багато. Достатньо реалізувати об'єкт-делегат, який ми встановимо для стовпця нашої таблиці за допомогою setItemDelegateForColumn() . Таким чином, відображення осередків цього стовпця буде здійснюватися не стандартними методами, а так, як ми хочемо, тобто у вигляді індикатора прогресу. Для визначення делегата успадкуємо клас QStyledItemDelegate:
У функцію paint() нашому делегату буде передано:
- Об'єкт класу QPainter, яким ми і малюватимемо індикатор;
- Набір опцій для відображення осередку QStyleOptionViewItem;
- Індекс моделі QModelIndex , за допомогою якого ми можемо отримати всю необхідну інформацію про комірку таблиці, яку ми маємо намалювати.
А ось і реалізація делегату:
У представленій реалізації ми створюємо набір опцій QStyleOptionProgressBar, у якому визначаємо стандартні параметри відображення індикатора прогресу. Зверніть увагу, що розмір індикатора ми визначаємо за допомогою QRect . Причому за основу взято розмір із переданих нам опцій option. Але цей розмір буде відповідати всій області осередку, а вона може виявитися занадто високою, через що індикатор виявиться занадто розтягнутим, тому для висоти ми вибрали своє значення.
Наприкінці функції paint() ми спочатку викликаємо реалізацію, передбачену в базовому класі, але передали в останньому аргументі порожній QModelIndex, щоб не виводити жодних даних моделі. Це потрібно, щоб наша комірка могла відображати деякі базові стани, типу рамки фокусу та підсвічування у разі вибору (можете прибрати цей рядок і переконатися, що нічого не відбувається, коли ви клацаєте по комірках). А сам індикатор прогресу із заготовленими параметрами малюється викликомQApplication::style()->drawControl() .
От і все. Залишилося замінити стандартний делегат у таблиці на наш. Це потрібно зробити в конструкторі віджету. Там, де ми створювали m_table . В результаті повинен вийти приблизно такий фрагмент:
Після запуску та пари натискань на кнопку Add я отримав таке:
Висновок
Ось ми й познайомилися із способом відображення індикатора прогресу у віджеті таблиці. Так само ви можете малювати у своєму делегаті взагалі все, що завгодно. З іншого боку, оскільки базові класи у QTableView , QTreeView і QListView загальні, одні й самі делегати працюватимуть у кожному з них.