Evgenii Legotckoi
Evgenii Legotckoi18 ноября 2015 г. 10:14

Qt/C++ - Урок 039. Как закрасить строку в QSqlTableModel по значению в столбце

Содержание

В уроке по работе с QSqlTableModel было подробно рассмотрено отображение таблицы данных из базы данных SQL . Но в связи с вопросом от одного из читателей, делаю небольшое дополнение к это примеру.

Вопрос состоял в том, как закрасить всю строку в зависимости от значения в одной из колонок. В примере по работе с QSqlTableModel производилось добавление в базу данных строк с датой, временем, псевдослучайным числом и сообщением об этом псевдослучайном числе. В связи с этим в качестве подопытных строк были выбраны строки, где псевдослучайное число равняется 41.

Для этого необходимо наследоваться от класса QSqlTableModel и переопределить метод QSqlTableModel::data(). После чего использовать в качестве модели данных новый класс наследник.


tablemodel.h

#ifndef TABLEMODEL_H
#define TABLEMODEL_H

#include <QObject>
#include <QSqlTableModel>

class TableModel : public QSqlTableModel
{
    Q_OBJECT
public:
    explicit TableModel(QObject *parent = 0);
    QVariant data(const QModelIndex &idx, int role) const;

signals:

public slots:
};

#endif // TABLEMODEL_H

tablemodel.cpp

Отмечу, что в первоначальном примере столбец 0 не отображается в таблице, поэтому выбираем получение данных из колонки 3, а не из колонки 2. Получение данных производится вызовом метода базового класса.

#include "tablemodel.h"
#include <QColor>

TableModel::TableModel(QObject *parent) : QSqlTableModel(parent)
{

}

QVariant TableModel::data(const QModelIndex &idx, int role) const
{
    if(role == Qt::BackgroundColorRole){
        if(QSqlTableModel::data(this->index(idx.row(), 3)).toInt() == 41){
            return QColor(Qt::red);
        }
    } else if(role == Qt::DisplayRole){
        return QSqlTableModel::data(idx);
    }
    return QVariant();
}

Итог

В результате получилось приложение, в котором отображается таблица, в которой закрашены красным цветом строки, где присутствует псевдослучайное число, равное 41. Причём подобный подход справедлив для всех классов, наследованных соответственно от QAbstractItemModel. То есть для QSqlQueryModel , QSqlRelationalTableModel и т.д.

Архив с примером урока из под ОС Ubuntu - внимательно проверяйте, по какому пути создаётся файл базы данных в класса DataBase.

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

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

Юрий
  • 8 октября 2017 г. 13:29

Как передать переменную в класс наследник?

Evgenii Legotckoi
  • 8 октября 2017 г. 14:37

А чутка подробнее ситуацию можете описать? Я не понял формулировки вопроса.

Юрий
  • 8 октября 2017 г. 15:20

Я хочу из БД дергать значения цветов из профиля пользователя. Как мне передать user_id?

Evgenii Legotckoi
  • 8 октября 2017 г. 15:38

То есть хотите подкрасить строку в таблице по цвету из профиля пользователя?

Юрий
  • 8 октября 2017 г. 16:35

Да именно так. Но как передать id пользователя не знаю.

Evgenii Legotckoi
  • 8 октября 2017 г. 16:44

Теоретически можно воспользоваться QSqlQuery, чтобы выдернуть данные из профиля прямо в методе data. А сам id можно дёрнуть через метод data, как взято значение в колонке через QSqlTableModel::data(this->index(idx.row(), 3)).toInt()

Юрий
  • 8 октября 2017 г. 17:06

Так id пользователя нет в данной таблице.

qry->prepare("select * from users where  id=" + id_user);

colorstatus1 = qry->value("colorstatus1").toString();

Variant value = QSqlQueryModel::data(idx, role);
if(role == Qt::BackgroundColorRole)
{
    if (idx.sibling(idx.row(),6).data( Qt::DisplayRole ).toInt() == 1)
{
    return qVariantFromValue(QColor(colorstatus1));
}
Evgenii Legotckoi
  • 8 октября 2017 г. 17:16

Ну я откуда знал, что у Вас нет этого id в таблице. И это разговор идёт про таблицу с профилями пользователей? Как тогда Вы делаете соответствие между пользователями и их данными, то есть цветами и т.д?

И вот этот код, что Вы привели, он вообще сработал?
Юрий
  • 8 октября 2017 г. 17:24

Суть такая, есть таблица, в ней меняются статусы и соответственно цвет строк. В профиле пользователя настраивается эти цвета. Код не работает. В том то и проблема. Пользователь проходит аутентификацию и я получаю его id., а вот как мне передать это id. Сигналы и слоты в данном случае не подходят, я просто не знаю(((

Evgenii Legotckoi
  • 8 октября 2017 г. 17:38

Так, хорошо. статусы меняются. То есть записываете состояние статуса в определённую таблицу... Но там же должен быть внешний ключ на пользователя? Если его нет, то сделайте внешний ключ на пользователя и тогда сможете без проблем дёргать статус и по нему прилагать нужный цвет. Обычно в таких случаях всегда в таблице профилей имеется внешний ключ на пользователя. Реляционные базы данных так и работают.

Юрий
  • 8 октября 2017 г. 17:46

В профиле пользователя настраивается только интерфейс. В одной таблице работают несколько пользователей и все хотят что бы у них статусы били разными цветами(как раз настраивается в профиле).  Я записывал данные в файл настроек

 QSettings *settings = new QSettings( "settings.conf", QSettings::IniFormat );
    settings->beginGroup( "ColorStatus" );
    settings->setValue("colorstatus1", ui->lineEdit_colorstatus1->text());
и потом просто читал данные из файла. Просто хочу реализовать через БД.
Evgenii Legotckoi
  • 8 октября 2017 г. 17:53

Ну понятно тогда. Сделайте тогда некую таблицу профилей вместо файла настроек, в которой будет храниться набор цветов для каждого варианта статуса. В таблице нужно создать несколько колонок, например четыре колонки для четырёх вариантов статуса. И обязательно внешний ключ на id пользователя. Когда пользователь аутентифицируется, то тогда можно будет дёрнуть через QSqlQuery, например, цвет статуса из таблицы профилей.

Юрий
  • 8 октября 2017 г. 18:11

Когда пользователь аутентифицируется, то тогда можно будет дёрнуть через QSqlQuery, например, цвет статуса из таблицы профилей.   

Можно как-то объявить переменную QString доступную из разных классов(форм или файлов .cpp)?

TableModel::TableModel(QObject *parent) : QSqlTableModel(parent)
{
    QSqlQuery *qry = new QSqlQuery();
    qry->prepare("select * from users where  id=" +id_user);
    if(qry->exec())
    { qry->next();
        colorstatus1 = qry->value("colorstatus1").toString();
    }
}
 
QVariant TableModel::data(const QModelIndex &idx, int role) const
{
    if(role == Qt::BackgroundColorRole){
      if (idx.sibling(idx.row(),6).data( Qt::DisplayRole ).toInt() == 1)
        {
            return qVariantFromValue(QColor(colorstatus1));
        }
    } else if(role == Qt::DisplayRole){
        return QSqlTableModel::data(idx);
    }
    return QVariant();
}
Evgenii Legotckoi
  • 8 октября 2017 г. 18:23

Ну можно сделать статическую переменную в заголовочном классе TableModel и как раз эта переменная и будет достаточной для того, чтобы она была видна во всех формах и классах, но это будет не очень хорошее решение как по мне.

Что вообще должна показывать эта самая TableModel? Список всех пользователей с их статусами?
Юрий
  • 8 октября 2017 г. 18:41

Статусы ремонта. "Ждем запчасти", "Без ремонта" и т.д. Я объявляю  public: static QString id_user;

А потом как получить эту переменную?
Юрий
  • 8 октября 2017 г. 21:10

Спасибо большое. Все разобрался))) Все оказалось  как всегда просто.

k
  • 23 марта 2018 г. 10:06

Почему-то при встраивании кода в урок 008, при редактировании строки, значения в виджетах пропадают и при сохранении изменений ничего не меняется. Где вызывается функция date?

k
  • 23 марта 2018 г. 10:41

Нашел ошибку. В функии data() в конце вместо QVariant(), вернул QSqlTableModel::data(idx,role). И все заработало!

МА
  • 27 мая 2020 г. 12:37

Вопрос- с переопределенным методом data и нашим классом- наследником- как удалять строки из модели?

            // Get all selections
            QModelIndexList indexes = ui->tableView->selectionModel()->selection().indexes();
            for (int i = 0; i < indexes.count(); ++i)
            {
                QModelIndex index = indexes.at(i);
                // To get the row/column numbers use index.row() / index.column()
                //qDebug() << "index.row() = " << index.row();
                model->removeRow(index.row());
                model->submitAll();
            }

метод model->removeRow(index.row());
не работает.

Evgenii Legotckoi
  • 28 мая 2020 г. 4:29

Для QSqlTableModel концептуально верным подходом являтся удаление запросом к базе данных.

МА
  • 28 мая 2020 г. 4:35
  • (ред.)

del

МА
  • 28 мая 2020 г. 4:35

Это как понять? Т.е. не через модель удалять, а через запрос к базе? А в чем тогда правильность? Если правильней с моделью работать, а не с базой в обход модели? Или я не так понял.

Evgenii Legotckoi
  • 28 мая 2020 г. 4:55

А. Да вы правы. Я немного попутал модель эту QSqlTableModel с QSqlQueryModel. У них есть разница, что QSqlQueryModel является read only, а поэтому функционал по удалению нужно дописывать.

Я думаю, всё дело в том, что или стратегия удаления не совсем верно настроена, либо там происходит какая-то ошибка.
Выведите в qDebug резальтат lastError() из модели. Там может быть по факту что угодно.

            QModelIndexList indexes = ui->tableView->selectionModel()->selection().indexes();
            for (int i = 0; i < indexes.count(); ++i)
            {
                QModelIndex index = indexes.at(i);
                // To get the row/column numbers use index.row() / index.column()
                //qDebug() << "index.row() = " << index.row();
                model->removeRow(index.row());
                model->submitAll();
                qDebug() << model->lastError();
            }
МА
  • 28 мая 2020 г. 5:06

QSqlError("", "", "")
Причем, если я использую Ваш подход- наследованный класс

TableModel  *model = new TableModel(this);

то не удаляет, как только делаю родной класс:

QSqlTableModel  *model = new QSqlTableModel (this); // работает

То удаляет и ошибка:
QSqlError("", "", "")
такая же.

Evgenii Legotckoi
  • 28 мая 2020 г. 5:19

После работы гляну проект. Пока нет мыслей.

МА
  • 28 мая 2020 г. 5:29

ок, буду ждать. Это странно, т.к. мы не переопределяли метод удаления.

Evgenii Legotckoi
  • 28 мая 2020 г. 5:35

Ну вот поэтому я и нахожусь в замешательстве. Вообще не должно было быть такого поведения. Разве что каким-то образом повлиял запрос в конструкторе, может быть не закрылась транзакция или что-то ещё, леший его знает.

МА
  • 28 мая 2020 г. 8:09
 model->setData(model->index(1, 0), 7);

Вот еще странность- не может сделать запись в уже имеющейся ячейке.
А в оригинальном пишет, но с глюком.

Evgenii Legotckoi
  • 28 мая 2020 г. 16:06

Да, метод data всё-таки влиял, я переписал его так и заработало удаление

QVariant TableModel::data(const QModelIndex &idx, int role) const
{
    if (role == Qt::BackgroundColorRole)
    {
        if (QSqlTableModel::data(this->index(idx.row(), 3)).toInt() == 1186278907)
        {
            return QColor(Qt::red);
        }
    }
    else if (role == Qt::DisplayRole)
    {
        return QSqlTableModel::data(idx, role);
    }
    return QSqlTableModel::data(idx, role);
}

Далее ваш код для удаления переписал иначе

QModelIndexList rowIndexes = ui->tableView->selectionModel()->selectedRows();
model->removeRows(rowIndexes.first().row(), rowIndexes.size());
model->submitAll();
model->select();

Это будет более эффективно

МА
  • 28 мая 2020 г. 16:08

Спасибо, завтра првоерю. А

 model->setData(model->index(1, 0), 7);

Тоже заработало?

Evgenii Legotckoi
  • 28 мая 2020 г. 16:14

Ну в моём примере, который в статье сработало так

model->setData(model->index(1, 1), 7);

Поскольку model->index(1, 0) - это индекс колонки id, которая скрыта, поэтому без дополнительных настроек таблицы вы не увидите результата

МА
  • 29 мая 2020 г. 7:27
            QModelIndexList rowIndexes = ui->tableView->selectionModel()->selectedRows();
            model->removeRows(rowIndexes.first().row(), rowIndexes.size());
            model->submitAll();
            model->select();

не работает. Вылетает с ошибкой.

Evgenii Legotckoi
  • 29 мая 2020 г. 7:30
  • (ред.)

У меня работает. Исправлял в проекте, который приложен к статье.
А что происходит в вашем коде, с учётом места вызова этого кода, я знать не могу ;)
Дебажьте и добавляйте условия, которые обезопасят вызов кода

a
  • 11 декабря 2022 г. 4:37

Здравствуйте.
В Вашем примере в строке QSqlTableModel::data(this->index(idx.row(), 3))
3 - это индекс столбца. А есть ли возможность в данном случае как-то использовать имя столбца?

Evgenii Legotckoi
  • 12 декабря 2022 г. 3:40

Добрый день. Нет, данный метод оперирует целочисленными значениями, которые являются индексами столбца и строки, для создания объекта QModelIndex, по которому уже метод data возвращает значение в ячейке.
Если ваш вопрос касается читаемости кода, то в таком случае правильным решением будет создать enum для столбцов, который будет отображать фактическое имя столбца.

    enum EColumnNames
    {
        FIRST_COLUMN = 1,
        SECOND_COLUMN = 2,
        THIRD_COLUMN = 3
    };

    QSqlTableModel::data(this->index(idx.row(), EColumnNames::THIRD_COLUMN));

a
  • 12 декабря 2022 г. 9:06

Спасибо за ответ. Нет, дело не в читаемости кода, в разных таблицах у меня есть столбцы с одинаковым именем, но с разными индексами. Хотел сделать решение по имени столбца для всех таблиц сразу.

Evgenii Legotckoi
  • 12 декабря 2022 г. 9:12
  • (ред.)

В этом случае вижу только какой-нибудь костыль в стиле перебора по всем индексам в заголовке с помощью методу headerData .
То есть пройтись в for цикле пока не будет совпадения названия столбца, запомнить индекс, а потом уже использовать его в методе data. Но опять же, headerData по умолчанию возвращает название колонки, но если делать перевод и переназывать колонки, то это решение покажет свою костыльность во всей красе. Так что это скорее только усложнит поддержку приложения.

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
d
  • dsfs
  • 26 апреля 2024 г. 11:56

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80баллов,
  • Очки рейтинга4
d
  • dsfs
  • 26 апреля 2024 г. 11:45

C++ - Тест 002. Константы

  • Результат:50баллов,
  • Очки рейтинга-4
d
  • dsfs
  • 26 апреля 2024 г. 11:35

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

  • Результат:73баллов,
  • Очки рейтинга1
Последние комментарии
k
kmssr9 февраля 2024 г. 2:43
Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко5 февраля 2024 г. 9:50
Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 декабря 2023 г. 18:30
Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 декабря 2023 г. 16:38
Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik19 декабря 2023 г. 5:01
Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Сейчас обсуждают на форуме
G
Gar22 апреля 2024 г. 12:46
Clipboard Как скопировать окно целиком в clipb?
DA
Dr Gangil Academics20 апреля 2024 г. 14:45
Unlock Your Aesthetic Potential: Explore MSC in Facial Aesthetics and Cosmetology in India Embark on a transformative journey with an msc in facial aesthetics and cosmetology in india . Delve into the intricate world of beauty and rejuvenation, guided by expert faculty and …
a
a_vlasov14 апреля 2024 г. 13:41
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
Павел Дорофеев
Павел Дорофеев14 апреля 2024 г. 9:35
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrex4 апреля 2024 г. 11:47
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

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