1 2 3 4 Робота з таблицями баз даних Найпростіший спосіб відображення інформації бази даних у вигляді таблиці полягає у використанні класів Qsqlquerymodel і Qtableview: Qsqlquerymodel model; model.setquery("select * from employee"); Qtableview view; view.setmodel(&model); view.show(); Але замість Qsqlquerymodel будемо використовувати клас Qsqltablemodel, що дозволяє працювати з таблицями баз даних на більш високому рівні, чим виконання Sql-Запитів. Тоді наведений вище фрагмент коду запишеться в такий спосіб: Qsqltablemodel model; model.settable("employee"); model.select(); Qtableview view; view.setmodel(&model); view.show(); Більш складний приклад: замість виконання Sql-Запиту SELECT * FROM employee WHERE salary >= 1000 ORDER BY id DESC для моделі Qsqltablemodel треба задати фільтр і умову сортування: Qsqltablemodel model = Qsqltablemodel(parent, db); model.settable("employee"); // Ім'я таблиці бази даних. model.setfilter("salary >= 1000"); // Умова WHERE. model.setsort(0, Qt::Descendingorder); // Сортування по убуванню id. model.select(); // Одержати дані. Після визначення моделі можна довідатися значення кожного поля будь-якого запису, наприклад: Qstring name = model.record(i).value("name").tostring(); або int salary = model.data(model.index(i, 3)).toint(); Для перебору всіх записів набору даних: for (int i = 0; i < model.rowcount(); ++i) { Qsqlrecord record = model.record(i); Qstring name = record.value("name").tostring(); double salary = record.value("salary").todouble(); ....... } У лістингу наведений програмний код для роботи з таблицею. Лістинг. Таблиця бази даних 1// Таблиця бази даних 2 3 #include 4 #include 5 6 int main(int argc, char *argv[]) { 7 8 Qapplication app(argc, argv); 9 10 Qtextcodec *codec = Qtextcodec::codecforname("CP1251"); 11 Qtextcodec::setcodecfortr(codec); 12 Qtextcodec::setcodecforcstrings(codec); 13 Qtextcodec::setcodecforlocale(codec); 14 15 Qsqldatabase db = Qsqldatabase::adddatabase("QODBC"); 16 db.setdatabasename("mysql_db1"); 17 db.setusername(""); 18 db.setpassword(""); 19 db.open(); 20 21// Qsqlquery q; 22// Для коректного відображення символів кирилиці: 23 24// q.exec(Qobject::tr("SET NAMES 'cp1251'")); 25 26 Qsqltablemodel *model = new Qsqltablemodel(); 27 model->settable("employee"); 28 29 model->insertrows(0, 1); 30 model->setdata(model->index(0, 0), 159); 31 model->setdata(model->index(0, 1), Qobject::tr("Сова")); 32 model->setdata(model->index(0, 2), Qdate(1985, 12, 31)); 33 model->setdata(model->index(0, 3), 12.34); 34 model->setdata(model->index(0, 4), 1); 35 model->submitall(); 36 37 model->seteditstrategy(Qsqltablemodel::Onfieldchange); 38 39 model->select(); 40 model->setheaderdata(0, Qt::Horizontal, 41 Qobject::tr("Номер")); 42 model->setheaderdata(1, Qt::Horizontal, 43 Qobject::tr("Ім'я")); 44 model->setheaderdata(2, Qt::Horizontal, 45 Qobject::tr("День народження")); 46 model->setheaderdata(3, Qt::Horizontal, 47 Qobject::tr("Зарплата")); 48 model->setheaderdata(4, Qt::Horizontal, 49 Qobject::tr("Одружений")); 50 51 Qtableview *view = new Qtableview(); 52 view->setmodel(model); 53 54 view->setalternatingrowcolors(true); 55 view->resizerowstocontents(); 56 view->resizecolumnstocontents(); 57 view->show(); 58 59 return app.exec(); 60 } Тепер можна змінювати дані в клітинках, при редагуванні чисел і дат автоматично відображаються кнопки інкременту/декременту. Але оскільки для елемента Qdoublespinbox за замовчуванням задане максимальне значення 99.99. Зрозуміло, спроба ввести число більше припустимого, кінчається невдачею. Крім того, після редагування першої ж клітинки таблиці, коли відбувається автоматичне поновлення даних, ширина стовпців і висота рядків змінюється, тому що розміри клітинок за замовчуванням відрізняються від тих, що встановилися в результаті однократного виконання методів resizerowstocontents і resizecolumnstocontents. Якщо ми прагнемо вносити різноманітні дані, виводити різні стовпці різним кольором, відображати галочки для полів логічного типу, використовувати календарик для введення дат, загалом, якось змінювати задані за замовчуванням параметри відображення й редагування клітинок, то в нас є дві можливості: розробляти свій клас моделі і вигляду таблиці або використовувати спеціальні об'єкти-делегати для її клітинок. Розробка моделі й вигляду таблиці БД У клітинках останнього стовпця таблиці, де зберігається тільки два можливі значення, будемо відображати елемент Qcheckbox і текст "Так" або "Ні". Крім того, заборонимо редагування першого стовпця, змінимо колір клітинок першого й останнього стовпців, а також параметри шрифту в другому стовпці. Для цього створимо свою модель таблиці, використавши в якості базового клас QSqlQueryModel. А щоб управляти розмірами гнізд таблиці, визначимо свій клас представлення таблиці на основі стандартного Qtableview. Нижче наведений текст програми. Лістинг. Модель і вигляд таблиці БД 1 #include 2 #include 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 4 #include 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.tobool()); 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 ORDER BY id"); 133 134 setheaderdata(0, Qt::Horizontal, tr("Номер")); 136 setheaderdata(1, Qt::Horizontal, tr("Ім'я")); 138 setheaderdata(2, Qt::Horizontal, tr("День народження")); 140 setheaderdata(3, Qt::Horizontal, tr("Адреса")); 142 setheaderdata(4, Qt::Horizontal, 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 } Для своєї моделі ми використовували базовий клас Qsqlquerymodel, що працює з довільним набором Sql-Запитів для читання й запису даних у БД. Але так нам потрібно докладно розписувати реалізацію методів data і setdata. У цьому випадку ми мали справу з єдиною таблицею бази даних, тому можна було в якості базового класу брати клас Qsqltablemodel. 1.7. Тестування та налагодження ПЗ Рисунок 11. Список автомобілів організації Рисунок 12. Таблиця зі списком шоферів Рисунок 13. Дані про операторів диспетчерської служби. 1 2 3 4 |