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 по умолчанию возвращает название колонки, но если делать перевод и переназывать колонки, то это решение покажет свою костыльность во всей красе. Так что это скорее только усложнит поддержку приложения.

Комментарии

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

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

  • Результат:50баллов,
  • Очки рейтинга-4
m
  • molni99
  • 25 октября 2024 г. 22:37

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

  • Результат:80баллов,
  • Очки рейтинга4
m
  • molni99
  • 25 октября 2024 г. 22:29

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

  • Результат:20баллов,
  • Очки рейтинга-10
Последние комментарии
ИМ
Игорь Максимов22 ноября 2024 г. 8:51
Django - Урок 017. Кастомизированная страница авторизации на Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii Legotckoi31 октября 2024 г. 11:37
Django - Урок 064. Как написать расширение для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZE19 октября 2024 г. 5:19
Читалка fb3-файлов на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов5 октября 2024 г. 4:51
Django - Урок 064. Как написать расширение для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55 июля 2024 г. 8:02
QML - Урок 016. База данных SQLite и работа с ней в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Сейчас обсуждают на форуме
Evgenii Legotckoi
Evgenii Legotckoi24 июня 2024 г. 12:11
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey115 ноября 2024 г. 3:04
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProject4 июня 2022 г. 0:49
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9Anonim25 октября 2024 г. 6:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

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