QCheckBox
и текст
"Да
" или "Нет
" (рис.). Кроме того, запретим
редактирование первого столбца, изменим цвет фона ячеек первого и последнего
столбцов, а также параметры шрифта во втором столбце.
Для этого определим свою модель таблицы, использовав в качестве базового
класс QSqlQueryModel
. А чтобы управлять размерами ячеек таблицы,
определим свой класс представления на основе стандартного
QTableView
. В листингах . и . приведён текст программы.
Листинг. Модель и представление таблицы БД (файл
examples-qt/db02/db02.h
)
1 #include <QSqlQueryModel> 2 #include <QTableView> 3 4 class MyModel : public QSqlQueryModel { 5 Q_OBJECT 6 public: 7 MyModel(QObject *parent = 0); 8 Qt::ItemFlags flags(const QModelIndex &index) const; 9 QVariant data(const QModelIndex &index, 10 int role = Qt::DisplayRole) const; 11 bool setData(const QModelIndex &index, 12 const QVariant &value, int role); 13 private: 14 void refresh(); 15 }; 16 17 class MyView : public QTableView { 18 Q_OBJECT 19 public: 20 MyView(QWidget *parent = 0); 21 private: 22 virtual void resizeEvent(QResizeEvent *event); 23 };
Листинг. Модель и представление таблицы БД (файл
examples-qt/db02/db02.cpp
)
1 // Таблица базы данных: пользовательская модель и представление 2 3 #include <QtGui> 4 #include <QtSql> 5 6 #include "db02.h" 7 8 MyModel::MyModel(QObject *parent) 9 : QSqlQueryModel(parent) { 10 refresh(); 11 } 12 13 Qt::ItemFlags MyModel::flags( 14 const QModelIndex &index) const { 15 16 Qt::ItemFlags flags = QSqlQueryModel::flags(index); 17 if (index.column() >= 1 && index.column() < 4) 18 flags |= Qt::ItemIsEditable; 19 if (index.column() == 4) 20 flags |= Qt::ItemIsUserCheckable; 21 return flags; 22 } 23 24 QVariant MyModel::data( 25 const QModelIndex &index, 26 int role) const { 27 28 QVariant value = QSqlQueryModel::data(index, role); 29 30 switch (role) { 31 32 case Qt::DisplayRole: // Данные для отображения 33 case Qt::EditRole: // Данные для редактирования 34 if (index.column() == 0) 35 return value.toString().prepend(tr("№")); 36 else if (index.column() == 2 && role == Qt::DisplayRole) 37 return value.toDate().toString("dd.MM.yyyy"); 38 else if (index.column() == 3 && role == Qt::DisplayRole) 39 return tr("%1") 40 .arg(value.toDouble(), 0, 'f', 2); 41 else if (index.column() == 4) 42 return value.toInt() != 0 ? tr("Да") : tr("Нет"); 43 else 44 return value; 45 46 case Qt::TextColorRole: // Цвет текста 47 if(index.column() == 1) 48 return qVariantFromValue(QColor(Qt::blue)); 49 else 50 return value; 51 52 case Qt::TextAlignmentRole: // Выравнивание 53 if(index.column() == 3) 54 return int(Qt::AlignRight | Qt::AlignVCenter); 55 else if(index.column() == 2 || index.column() == 4) 56 return int(Qt::AlignHCenter | Qt::AlignVCenter); 57 else 58 return int(Qt::AlignLeft | Qt::AlignVCenter); 59 60 case Qt::FontRole: // Шрифт 61 if(index.column() == 1) { 62 QFont font = QFont("Helvetica", 10, QFont::Bold); 63 return qVariantFromValue(font); 64 }else 65 return value; 66 67 case Qt::BackgroundColorRole: { // Цвет фона 68 int a = (index.row() % 2) ? 14 : 0; 69 if(index.column() == 0) 70 return qVariantFromValue(QColor(220,240-a,230-a)); 71 else if(index.column() == 4) 72 return qVariantFromValue(QColor(200,220-a,255-a)); 73 else 74 return value; 75 } 76 case Qt::CheckStateRole: // Галочка 77 if (index.column() == 4) 78 return (QSqlQueryModel::data(index).toInt() != 0) ? 79 Qt::Checked : Qt::Unchecked; 80 else 81 return value; 82 83 case Qt::SizeHintRole: // Размер ячейки 84 if (index.column() == 0) 85 return QSize(70, 10); 86 if (index.column() == 4) 87 return QSize(60, 10); 88 else 89 return QSize(110, 10); 90 } 91 return value; 92 } 93 94 bool MyModel::setData( 95 const QModelIndex &index, 96 const QVariant &value, 97 int /* role */) { 98 if (index.column() < 1 || index.column() > 4) 99 return false; 100 101 QModelIndex primaryKeyIndex = QSqlQueryModel::index( 102 index.row(), 0); 103 int id = QSqlQueryModel::data(primaryKeyIndex).toInt(); 104 105 //clear(); // Если надо полностью перерисовать таблицу. 106 107 bool ok; 108 QSqlQuery query; 109 if (index.column() == 1) { 110 query.prepare("update employee set name = ? where id = ?"); 111 query.addBindValue(value.toString()); 112 query.addBindValue(id); 113 }else if(index.column() == 2) { 114 query.prepare("update employee set born = ? where id = ?"); 115 query.addBindValue(value.toDate()); 116 query.addBindValue(id); 117 }else if(index.column() == 3) { 118 query.prepare("update employee set salary = ? where id = ?"); 119 query.addBindValue(value.toDouble()); 120 query.addBindValue(id); 121 }else if(index.column() == 4) { 122 query.prepare("update employee set married = ? where id = ?"); 123 query.addBindValue(value.toInt()); 124 query.addBindValue(id); 125 } 126 ok = query.exec(); 127 refresh(); 128 return ok; 129 } 130 131 void MyModel::refresh() { 132 setQuery("select * from employee"); 133 134 setHeaderData(0, Qt::Horizontal, 135 tr("Табельн.\nномер")); 136 setHeaderData(1, Qt::Horizontal, 137 tr("Имя")); 138 setHeaderData(2, Qt::Horizontal, 139 tr("День рождения")); 140 setHeaderData(3, Qt::Horizontal, 141 tr("Зарплата")); 142 setHeaderData(4, Qt::Horizontal, 143 tr("Женат/\nзамужем")); 144 } 145 146 //------------------------------------ 147 MyView::MyView(QWidget *parent) 148 : QTableView(parent) { 149 150 } 151 152 void MyView::resizeEvent(QResizeEvent *event) { 153 resizeRowsToContents(); 154 resizeColumnsToContents(); 155 QTableView::resizeEvent(event); 156 } 157 158 //------------------------------------ 159 int main(int argc, char *argv[]) { 160 161 QApplication app(argc, argv); 162 163 QTextCodec *codec = QTextCodec::codecForName("CP1251"); 164 QTextCodec::setCodecForTr(codec); 165 QTextCodec::setCodecForCStrings(codec); 166 167 QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); 168 db.setDatabaseName("db1"); 169 db.setUserName("root"); 170 db.setPassword("password"); 171 db.open(); 172 173 // QSqlQuery q; 174 // Для корректного отображения кириллицы, возможно, 175 // придётся установить кодировку: 176 //q.exec(QObject::tr("SET NAMES 'cp1251'")); 177 178 MyModel *model = new MyModel(); 179 180 MyView *view = new MyView(); 181 view->setModel(model); 182 183 view->setAlternatingRowColors(true); 184 view->resizeRowsToContents(); 185 view->resizeColumnsToContents(); 186 view->show(); 187 188 return app.exec(); 189 }
refresh
(131), в котором указаны
заголовки столбцов и текст SQL-запроса, выполняемый для получения данных из
БД.
flags
переопределили свойства ячеек таблицы.
Qt::ItemIsEditable
.
Qt::ItemIsUserCheckable
, в результате во всех его ячейках перед
текстовой меткой будет отображаться элемент QCheckBox
.
data
переопределяются данные, "хранящиеся" в
ячейках таблицы. В зависимости от параметра role
(роль), это либо
сами данные, читаемые из БД, либо параметры их отображения.
role
: Qt::DisplayRole
(данные для
отображения ячейки таблицы), Qt::EditRole
(данные для режима
редактирования), Qt::TextColorRole
(цвет текста),
Qt::TextAlignmentRole
(выравнивание текста),
Qt::FontRole
(параметры шрифта),
Qt::BackgroundColorRole
(цвет фона ячейки),
Qt::CheckStateRole
(надо ли отображать элемент
QCheckBox
), Qt::SizeHintRole
(предпочитаемые размеры
ячейки).
setData
переопределяются данные, которые
будут записываться в БД.
id
(целочисленный
идентификатор) изменяемой записи.
main
повторяет текст предыдущей
программы, только в (178-181) используется наш класс модели и класс для
представления таблицы. Для своей модели мы использовали базовый класс QSqlQueryModel
,
работающий с произвольным набором SQL-запросов для чтения и записи данных в БД.
Но за всё приходится платить: нам пришлось подробно расписывать реализацию
методов data
и setData
. В данном случае мы имели дело
с единственной таблицей базы данных, поэтому можно было в качестве базового
класса взять QSqlTableModel
.
Проверьте, как работает эта программа. Намного лучше, чем предыдущая, не
правда ли? Размеры ячеек теперь не "прыгают" при редактировании, а при щелчке
левой кнопкой мыши по элементу QCheckBox
в ячейках последнего
столбца автоматически изменяется текстовая метка "Да/Нет". Но ввести трёхзначную
зарплату всё ещё не получается. Мы исправим данный недостаток в следующем
разделе.