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

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

А теперь небольшая статья о настройке поведения ячеек с помощью делегатов в QTableView.
Эта статья является модификацией поведения таблицы в одной старой статье, а именно Qt/C++ - Tutorial 039. Как заполнить строку в QSqlTableModel по значению в столбце . На самом деле та старая статья никак не влияет на содержание этой статьи, но таблица для примера будет взята из того урока.

В качестве задания был выбран цвет линии при наведении курсора мыши.

Это будет выглядеть следующим образом


Для реализации этого функционала напишем класс CustomDelegate, который будет установлен в столбцах таблицы для управления перекраской фона ячеек. Перекраской фонарей ячеек.

CustomDelegate.h

Мы наследуем от класса QStyledItemDelegate и переопределяем метод paint .

#ifndef CUSTOMDELEGATE_H
#define CUSTOMDELEGATE_H

#include <QStyledItemDelegate>

class CustomDelegate : public QStyledItemDelegate
{
    using BaseClass = QStyledItemDelegate;

public:
    CustomDelegate(QObject* parent = nullptr);

    virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
};

#endif // CUSTOMDELEGATE_H

CustomDelegate.cpp

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

#include "customdelegate.h"

#include <QPainter>
#include <QAbstractItemView>

CustomDelegate::CustomDelegate(QObject* parent) : BaseClass(parent)
{
}

void CustomDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if (QAbstractItemView* tableView = qobject_cast<QAbstractItemView*>(this->parent()))
    {
        QModelIndex hover = tableView->indexAt(tableView->viewport()->mapFromGlobal(QCursor::pos()));
        if (hover.row() == index.row())
        {
            painter->fillRect(option.rect, Qt::red);
        }
    }

    BaseClass::paint(painter, option, index);
}

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

Делегат должен быть установлен в каждом столбце таблицы. И вам также нужно включить отслеживание курсора мыши внутри QTableView.

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

Вывод

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

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

IscanderChe
  • 4 июня 2020 г. 16:30
  • (ред.)

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

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

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

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

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

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

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

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

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

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

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

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
S
  • SusLik
  • 28 мая 2023 г. 13:34

C++ - Тест 001. Первая программа и типы данных

  • Результат:53баллов,
  • Очки рейтинга-4
S
  • SusLik
  • 28 мая 2023 г. 13:27

C++ - Тест 003. Условия и циклы

  • Результат:57баллов,
  • Очки рейтинга-2
g

C++ - Тест 005. Структуры и Классы

  • Результат:100баллов,
  • Очки рейтинга10
Последние комментарии
Evgenii Legotckoi
Evgenii Legotckoi25 мая 2023 г. 14:49
Как написать игру на Qt - Урок 2. Анимация героя игры (2D) Код на строчка 184-198 вызывает перерисовку области на каждый 4-й такт счётчика. По той логике не нужно перерисовывать объект постоянно, достаточно реже, чем выполняется игровой слот. А слот вып…
J
JonnyJo21 мая 2023 г. 20:49
Как написать игру на Qt - Урок 2. Анимация героя игры (2D) Евгений, благодарю! Всё равно не совсем понимаю :( Если муха двигает ножками только при нажатии клавиш перемещение, то что, собственно, делает код со строк 184-198 в triangle.cpp? В этих строчка…
Evgenii Legotckoi
Evgenii Legotckoi21 мая 2023 г. 15:57
Как написать игру на Qt - Урок 2. Анимация героя игры (2D) Добрый день. slotGameTimer срабатывает по таймеру и при каждой сработке countForSteps увеличивается на 1, это не зависит от нажатия клавиш, нажатая клавиша лишь определяет положение ножек, котор…
J
JonnyJo20 мая 2023 г. 21:27
Как написать игру на Qt - Урок 2. Анимация героя игры (2D) Евгений, здравствуйте! Подскажите, а почему при нажатии одной клавиши переменная countForSteps увеличивается не на 1, на 4, ведь одно действие даёт увеличение этой переменной только на единицу? …
Сейчас обсуждают на форуме
Evgenii Legotckoi
Evgenii Legotckoi16 апреля 2023 г. 14:07
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Да, это возможно. Но подобные вещи лучше запускать через celery. То есть drf принимает команду, и после этого регистрирует задачу в celery, котроый уже асинхронно всё это выполняет. В противном …
АБ
Алексей Бобров15 декабря 2021 г. 6:03
Sorting the added QML elements in the ListModel I am writing an alarm clock in QML, I am required to sort the alarms in ascending order (depending on the date or time (if there are several alarms on the same day). I've done the sorting …
Evgenii Legotckoi
Evgenii Legotckoi29 марта 2023 г. 14:11
Замена поля ManyToMany Картинки точно нужно хранить в медиа директории на сервере, а для обращения использовать ImageField. Который будет хранить только путь к изображению на сервере. Хранить изображения в базе данных…
Evgenii Legotckoi
Evgenii Legotckoi24 апреля 2023 г. 13:22
Пакеты данных между сервером и клиентами Привет. Если классы имеют что-то общее в полях, а также общую идеологию и их можно вписать в иерархию наследования, то в первую очередь переписать так, чтобы один базовый класс объединял в…

Следите за нами в социальных сетях