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

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

А тепер невелика стаття про кастомізації поведінки осередків за допомогою делегатів в QTableView.
Ця стаття є модифікацією поведінки таблиці в одній старій статті, а саме Qt/C++ - Урок 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);

Висновок

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

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

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

4

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

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

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

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

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

ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
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