Программирование на C++ с использованием библиотеки Qt4

         

Модель и представление таблицы БД (файл 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 };


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 }




(8-10) В конструкторе модели таблицы вызвали конструктор базового класса и определённый ниже метод refresh (131), в котором указаны заголовки столбцов и текст SQL-запроса, выполняемый для получения данных из БД. (13-22) В методе flags переопределили свойства ячеек таблицы.

(16) Получили значения флагов-свойств, которые определены для данного столбца в базовом классе. (17-18) Для всех столбцов, кроме первого (вернее, нулевого) и последнего, выставили флаг разрешения редактирования Qt::ItemIsEditable. (19-20) Для последнего столбца установили признак Qt::ItemIsUserCheckable, в результате во всех его ячейках перед текстовой меткой будет отображаться элемент QCheckBox. (24-92) В методе data переопределяются данные, "хранящиеся" в ячейках таблицы. В зависимости от параметра role (роль), это либо сами данные, читаемые из БД, либо параметры их отображения. (28) Получили значение, определённое в базовом классе. (30-90) Определяем параметры ячейки таблицы, в зависимости от значения параметра role: Qt::DisplayRole (данные для отображения ячейки таблицы), Qt::EditRole (данные для режима редактирования), Qt::TextColorRole (цвет текста), Qt::TextAlignmentRole (выравнивание текста), Qt::FontRole (параметры шрифта), Qt::BackgroundColorRole (цвет фона ячейки), Qt::CheckStateRole (надо ли отображать элемент QCheckBox), Qt::SizeHintRole (предпочитаемые размеры ячейки). (34-35) Для самого первого столбца перед числом добавили символ "№". (36-37) Для столбца с датами рождения в режиме отображения задали формат "число.месяц.год" (по умолчанию действует формат "год-месяц-число"). (38-40) Для столбца зарплат в режиме отображения установили точность два знака после запятой. (41-42) В последнем столбце отображаем текст "Да" или "Нет". (43-44) Для всех остальных стрлбцов (остался только столбец с именами работников) ничего не изменяем. (46-50) Для столбца с именами установили голубой цвет символов, для всех остальных -- цвет по умолчанию. (52-58) Числа выравниваем по правому краю, даты и надписи "Да/Нет" -- по центру, остальные ячейки -- по левому краю. Во всех случаях центрируем по вертикали. (60-65) Для столбца имён задали жирный шрифт "Helvetica" размером 10 пунктов, для всех остальных ячеек -- шрифт по умолчанию. (67-74) Установили цвет фона для ячеек самого первого и последнего столбцов (для чётных строк -- немного светлее, чем для нечётных). Для всех остальных столбцов -- цвет фона по умолчанию. (76-81) Для ячеек последнего столбца устанавливаем галочку или сбрасываем её, в зависимости от значения, хранящегося в БД. (83-90) Установили предпочтительные размеры ячеек. (94-129) В методе setData переопределяются данные, которые будут записываться в БД. (98-99) Могут изменяться только ячейки из столбцов с 1 по 4. (101-103) Выяснили значение поля id (целочисленный идентификатор) изменяемой записи. (107-128) Определили текст SQL-запроса для обновления данных каждого столбца таблицы. (131-144) Задали текст SQL-запроса для чтения данных из БД и отображаемые заголовки столбцов таблицы. (147-150) В конструкторе представления таблицы не забыли вызвать конструктор базового класса. (152-156) Определяем действия, выполняемые при изменении размеров таблицы (в данном случае делается автоматическая подгонка размеров по содержимому ячеек). (159-189) Процедура main повторяет текст предыдущей программы, только в (178-181) используется наш класс модели и класс для представления таблицы.

Для своей модели мы использовали базовый класс QSqlQueryModel, работающий с произвольным набором SQL-запросов для чтения и записи данных в БД. Но за всё приходится платить: нам пришлось подробно расписывать реализацию методов data и setData. В данном случае мы имели дело с единственной таблицей базы данных, поэтому можно было в качестве базового класса взять QSqlTableModel.

Проверьте, как работает эта программа. Намного лучше, чем предыдущая, не правда ли? Размеры ячеек теперь не "прыгают" при редактировании, а при щелчке левой кнопкой мыши по элементу QCheckBox в ячейках последнего столбца автоматически изменяется текстовая метка "Да/Нет". Но ввести трёхзначную зарплату всё ещё не получается. Мы исправим данный недостаток в следующем разделе.


Разработка модели и представления таблицы БД


Решим сначала простую задачу: в ячейках последнего столбца таблицы, где хранится только два возможных значения, будем отображать элемент QCheckBox и текст "Да" или "Нет" (рис.). Кроме того, запретим редактирование первого столбца, изменим цвет фона ячеек первого и последнего столбцов, а также параметры шрифта во втором столбце.

Для этого определим свою модель таблицы, использовав в качестве базового класс QSqlQueryModel. А чтобы управлять размерами ячеек таблицы, определим свой класс представления на основе стандартного QTableView. В листингах . и . приведён текст программы.