- 1. tablemodel.h
- 2. tablemodel.cpp
- 3. Итог
В уроке по работе с 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.
Как передать переменную в класс наследник?
А чутка подробнее ситуацию можете описать? Я не понял формулировки вопроса.
Я хочу из БД дергать значения цветов из профиля пользователя. Как мне передать user_id?
То есть хотите подкрасить строку в таблице по цвету из профиля пользователя?
Да именно так. Но как передать id пользователя не знаю.
Теоретически можно воспользоваться QSqlQuery, чтобы выдернуть данные из профиля прямо в методе data. А сам id можно дёрнуть через метод data, как взято значение в колонке через QSqlTableModel::data(this->index(idx.row(), 3)).toInt()
Так id пользователя нет в данной таблице.
Ну я откуда знал, что у Вас нет этого id в таблице. И это разговор идёт про таблицу с профилями пользователей? Как тогда Вы делаете соответствие между пользователями и их данными, то есть цветами и т.д?
Суть такая, есть таблица, в ней меняются статусы и соответственно цвет строк. В профиле пользователя настраивается эти цвета. Код не работает. В том то и проблема. Пользователь проходит аутентификацию и я получаю его id., а вот как мне передать это id. Сигналы и слоты в данном случае не подходят, я просто не знаю(((
Так, хорошо. статусы меняются. То есть записываете состояние статуса в определённую таблицу... Но там же должен быть внешний ключ на пользователя? Если его нет, то сделайте внешний ключ на пользователя и тогда сможете без проблем дёргать статус и по нему прилагать нужный цвет. Обычно в таких случаях всегда в таблице профилей имеется внешний ключ на пользователя. Реляционные базы данных так и работают.
В профиле пользователя настраивается только интерфейс. В одной таблице работают несколько пользователей и все хотят что бы у них статусы били разными цветами(как раз настраивается в профиле). Я записывал данные в файл настроек
Ну понятно тогда. Сделайте тогда некую таблицу профилей вместо файла настроек, в которой будет храниться набор цветов для каждого варианта статуса. В таблице нужно создать несколько колонок, например четыре колонки для четырёх вариантов статуса. И обязательно внешний ключ на id пользователя. Когда пользователь аутентифицируется, то тогда можно будет дёрнуть через QSqlQuery, например, цвет статуса из таблицы профилей.
Можно как-то объявить переменную QString доступную из разных классов(форм или файлов .cpp)?
Ну можно сделать статическую переменную в заголовочном классе TableModel и как раз эта переменная и будет достаточной для того, чтобы она была видна во всех формах и классах, но это будет не очень хорошее решение как по мне.
Статусы ремонта. "Ждем запчасти", "Без ремонта" и т.д. Я объявляю public: static QString id_user;
Спасибо большое. Все разобрался))) Все оказалось как всегда просто.
Почему-то при встраивании кода в урок 008, при редактировании строки, значения в виджетах пропадают и при сохранении изменений ничего не меняется. Где вызывается функция date?
Нашел ошибку. В функии data() в конце вместо QVariant(), вернул QSqlTableModel::data(idx,role). И все заработало!
Вопрос- с переопределенным методом data и нашим классом- наследником- как удалять строки из модели?
метод model->removeRow(index.row());
не работает.
Для QSqlTableModel концептуально верным подходом являтся удаление запросом к базе данных.
del
Это как понять? Т.е. не через модель удалять, а через запрос к базе? А в чем тогда правильность? Если правильней с моделью работать, а не с базой в обход модели? Или я не так понял.
А. Да вы правы. Я немного попутал модель эту QSqlTableModel с QSqlQueryModel. У них есть разница, что QSqlQueryModel является read only, а поэтому функционал по удалению нужно дописывать.
Я думаю, всё дело в том, что или стратегия удаления не совсем верно настроена, либо там происходит какая-то ошибка.
Выведите в qDebug резальтат lastError() из модели. Там может быть по факту что угодно.
QSqlError("", "", "")
Причем, если я использую Ваш подход- наследованный класс
то не удаляет, как только делаю родной класс:
То удаляет и ошибка:
QSqlError("", "", "")
такая же.
После работы гляну проект. Пока нет мыслей.
ок, буду ждать. Это странно, т.к. мы не переопределяли метод удаления.
Ну вот поэтому я и нахожусь в замешательстве. Вообще не должно было быть такого поведения. Разве что каким-то образом повлиял запрос в конструкторе, может быть не закрылась транзакция или что-то ещё, леший его знает.
Вот еще странность- не может сделать запись в уже имеющейся ячейке.
А в оригинальном пишет, но с глюком.
Да, метод data всё-таки влиял, я переписал его так и заработало удаление
Далее ваш код для удаления переписал иначе
Это будет более эффективно
Спасибо, завтра првоерю. А
Тоже заработало?
Ну в моём примере, который в статье сработало так
Поскольку model->index(1, 0) - это индекс колонки id, которая скрыта, поэтому без дополнительных настроек таблицы вы не увидите результата
не работает. Вылетает с ошибкой.
У меня работает. Исправлял в проекте, который приложен к статье.
А что происходит в вашем коде, с учётом места вызова этого кода, я знать не могу ;)
Дебажьте и добавляйте условия, которые обезопасят вызов кода
Здравствуйте.
В Вашем примере в строке QSqlTableModel::data(this->index(idx.row(), 3))
3 - это индекс столбца. А есть ли возможность в данном случае как-то использовать имя столбца?
Добрый день. Нет, данный метод оперирует целочисленными значениями, которые являются индексами столбца и строки, для создания объекта QModelIndex, по которому уже метод data возвращает значение в ячейке.
Если ваш вопрос касается читаемости кода, то в таком случае правильным решением будет создать enum для столбцов, который будет отображать фактическое имя столбца.
Спасибо за ответ. Нет, дело не в читаемости кода, в разных таблицах у меня есть столбцы с одинаковым именем, но с разными индексами. Хотел сделать решение по имени столбца для всех таблиц сразу.
В этом случае вижу только какой-нибудь костыль в стиле перебора по всем индексам в заголовке с помощью методу headerData .
То есть пройтись в for цикле пока не будет совпадения названия столбца, запомнить индекс, а потом уже использовать его в методе data. Но опять же, headerData по умолчанию возвращает название колонки, но если делать перевод и переназывать колонки, то это решение покажет свою костыльность во всей красе. Так что это скорее только усложнит поддержку приложения.