Evgenii Legotckoi
04 червня 2020 р. 03:30

Qt/C ++ - Урок 091. Як написати кастомний делегат керуючий підсвічуванням рядки в таблиці

А тепер невелика стаття про кастомізації поведінки осередків за допомогою делегатів в QTableView.
Ця стаття є модифікацією поведінки таблиці в одній старій статті, а саме Qt/C++ - Урок 039. Як зафарбувати рядок в QSqlTableModel за значенням в стовпці . По суті та стара стаття не має впливу на вміст даної статті, але таблиця для прикладу буде взята з того уроку.

Як завдання вибрано зміна кольору рядка при наведенні курсору миші.

Виглядати це буде наступним чином


Для реалізації подібного функціоналу напишемо клас CustomDelegate, який буде встановлюватися в колонки таблиці, щоб управляти перефарбою фону осередків.

CustomDelegate.h

Наслідуючи від класу QStyledItemDelegate і перевизначати метод paint .

  1. #ifndef CUSTOMDELEGATE_H
  2. #define CUSTOMDELEGATE_H
  3.  
  4. #include <QStyledItemDelegate>
  5.  
  6. class CustomDelegate : public QStyledItemDelegate
  7. {
  8. using BaseClass = QStyledItemDelegate;
  9.  
  10. public:
  11. CustomDelegate(QObject* parent = nullptr);
  12.  
  13. virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
  14. };
  15.  
  16. #endif // CUSTOMDELEGATE_H
  17.  

CustomDelegate.cpp

У методі paint ми перевіряємо, чи знаходиться курсор на одній в рядку клітинки, яка піддалася перемальовуванні в процес руху курсору в області QTableView керування, і якщо це так, то заповнюємо фон комірки необхідним кольором.

  1. #include "customdelegate.h"
  2.  
  3. #include <QPainter>
  4. #include <QAbstractItemView>
  5.  
  6. CustomDelegate::CustomDelegate(QObject* parent) : BaseClass(parent)
  7. {
  8. }
  9.  
  10. void CustomDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
  11. {
  12. if (QAbstractItemView* tableView = qobject_cast<QAbstractItemView*>(this->parent()))
  13. {
  14. QModelIndex hover = tableView->indexAt(tableView->viewport()->mapFromGlobal(QCursor::pos()));
  15. if (hover.row() == index.row())
  16. {
  17. painter->fillRect(option.rect, Qt::red);
  18. }
  19. }
  20.  
  21. BaseClass::paint(painter, option, index);
  22. }
  23.  

Установка делегата в QTableView

Делегат повинен встановлюватися в кожну колонку в таблиці. А також необхідно включити відстеження пересування курсору миші всередині QTableView.

  1. ui->tableView->setItemDelegateForColumn(0, new CustomDelegate(ui->tableView));
  2. ui->tableView->setItemDelegateForColumn(1, new CustomDelegate(ui->tableView));
  3. ui->tableView->setItemDelegateForColumn(2, new CustomDelegate(ui->tableView));
  4. ui->tableView->setItemDelegateForColumn(3, new CustomDelegate(ui->tableView));
  5. ui->tableView->setItemDelegateForColumn(4, new CustomDelegate(ui->tableView));
  6. ui->tableView->setMouseTracking(true);

Висновок

Дуже важливо розуміти, яка частина коду і за що відповідає з точки зору архітектури програми.
Пересування курсора миші є виключно користувальницької активністю, яка не має ніякого відношення до даних.
Тому намагайтеся уникати додавання подібного функціоналу в модель даних, оскільки це спочатку буде неправильним підходом.
Краще написати трохи більше програмного коду і використовувати делегат, ніж змішувати дані і їх уявлення.
Тобто в такому разі зміна поведінки програми не повинно опускатися нижче кончини або окремого делегат уявлення.

Рекомендовані статті на цю тему

По статті запитували0питання

4

Вам це подобається? Поділіться в соціальних мережах!

IscanderChe
  • 04 червня 2020 р. 16:30
  • (відредаговано)

День добрый.
Зачем нужна вот эта строка:

  1. using BaseClass = QStyledItemDelegate;

Всё, разобрался. :)

Evgenii Legotckoi
  • 04 червня 2020 р. 17:12
  • (відредаговано)

Добрый день. Удобства ради. В больших проектах удобнее вызывать BaseClass, чем постоянно смотреть, от чего конкретно наследован текущий класс. Экономит время.

IscanderChe
  • 04 червня 2020 р. 17:59

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

Evgenii Legotckoi
  • 04 червня 2020 р. 18:08

Во все колонки установили? Нужно на все колонки устанавливать.

IscanderChe
  • 04 червня 2020 р. 18:10

Да, во все колонки.

IscanderChe
  • 04 червня 2020 р. 22:10

Полностью скопировал пример - всё правильно работает. Значит, где-то у меня ошибки в тестовом проекте. Буду разбираться. Извините за беспокойство. :)

IscanderChe
  • 05 червня 2020 р. 12:27

Разобрался. У вас изначально в проекте были вот эти настройки:

  1. ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
  2. ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);

У меня же их не было, поэтому и выделялись отдельные ячейки.

Evgenii Legotckoi
  • 05 червня 2020 р. 12:31

Понятно. Я не обратил внимания на то, что там было в старом коде по настройкам строк :)

IscanderChe
  • 05 червня 2020 р. 12:34

Сижу, размышляю: можно ли переписать делегата так, чтобы независимо от настроек строк выделялись строки?

Evgenii Legotckoi
  • 05 червня 2020 р. 12:39

По-моему, смысла в этом нет особого. Если делегат будет игнорировать настройки таблицы, то это приведёт ещё к большему непониманию, что вообще происходит, для программиста, который после вас будет смотреть на ваш проект.

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
  • Останні коментарі
  • Evgenii Legotckoi
    16 квітня 2025 р. 17:08
    Благодарю за отзыв. И вам желаю всяческих успехов!
  • IscanderChe
    12 квітня 2025 р. 17:12
    Добрый день. Спасибо Вам за этот проект и отдельно за ответы на форуме, которые мне очень помогли в некоммерческих пет-проектах. Профессиональным программистом я так и не стал, но узнал мно…
  • AK
    01 квітня 2025 р. 11:41
    Добрый день. В данный момент работаю над проектом, где необходимо выводить звук из программы в определенное аудиоустройство (колонки, наушники, виртуальный кабель и т.д). Пишу на Qt5.12.12 поско…
  • Evgenii Legotckoi
    09 березня 2025 р. 21:02
    К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
  • VP
    09 березня 2025 р. 16:14
    Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…