Назад Содержание Вперед

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

Решим сначала простую задачу: в ячейках последнего столбца таблицы, где хранится только два возможных значения, будем отображать элемент 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 }

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

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

Назад Содержание Вперед