Evgenii Legotckoi
4 июня 2020 г. 3:30

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

А теперь небольшая статья о настройке поведения ячеек с помощью делегатов в QTableView.
Эта статья является модификацией поведения таблицы в одной старой статье, а именно Qt/C++ - Tutorial 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
  • 4 июня 2020 г. 16:30
  • (ред.)

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

  1. using BaseClass = QStyledItemDelegate;

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

Evgenii Legotckoi
  • 4 июня 2020 г. 17:12
  • (ред.)

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

IscanderChe
  • 4 июня 2020 г. 17:59

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

Evgenii Legotckoi
  • 4 июня 2020 г. 18:08

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

IscanderChe
  • 4 июня 2020 г. 18:10

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

IscanderChe
  • 4 июня 2020 г. 22:10

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

IscanderChe
  • 5 июня 2020 г. 12:27

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

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

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

Evgenii Legotckoi
  • 5 июня 2020 г. 12:31

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

IscanderChe
  • 5 июня 2020 г. 12:34

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

Evgenii Legotckoi
  • 5 июня 2020 г. 12:39

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

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь