QML and QSqlTableModel

I wrote a simple class derived from QsqlRelationalTableModel to facilitate the use of such classes with QML, without manually defining the roles.

  1. class QLSqlTableModel : public QSqlRelationalTableModel
  2. {
  3.     Q_OBJECT
  4. private:
  5.     QHash<int, QByteArray> roles;
  6. public:
  7.     QLSqlTableModel(QObject *parent = 0);
  8.     ~QLSqlTableModel();
  9.     QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
  10.     void generateRoleNames();
  11. }
  12.  
  13.  
  14. QVariant QLSqlTableModel::data ( const QModelIndex & index, int role ) const
  15. {
  16.     if (!index.isValid())
  17.         return QVariant();
  18.     m.setTable(this->tableName());
  19.     m.select();
  20.     if(index.row() >= m.rowCount())
  21.         return QString("");
  22.     for (int i = 0; i < columnCount(); i++) {
  23.         QSqlRelation relation = this->relation(i);
  24.         if (relation.isValid()) {
  25.             m.setRelation(i, relation);
  26.             m.select();
  27.             QSqlRecord r = m.record(index.row());
  28.             return r.value(QString(roles.value(role)));
  29.         }
  30.     }
  31.     m.setTable(this->tableName());
  32.     m.select();
  33.     if(index.row() >= m.rowCount())
  34.         return QString("");
  35.     QSqlRecord r = m.record(index.row());
  36.     return r.value(QString(roles.value(role)));
  37. }

The data method returns the value of the role used. If there is a relationship in the table, i search the column with relation and return the correct value.. Note that empty string is returned when the item is not found e not QVariant value, in order to have a correct visualization in QML.

  1. void QLSqlTableModel::generateRoleNames()
  2. {
  3.     roles.clear();
  4.     for (int i = 0; i < this->columnCount(); i++) {
  5.         roles[Qt::UserRole + i] = this->headerData(i, Qt::Horizontal).toByteArray();
  6.        
  7.     }
  8.     setRoleNames(roles);
  9. }

The generateRoleNames method creates the roles called as the table columns specified in the header.

Example:

Tables:

  1. query.exec("create table IF NOT EXISTS items (id integer primary key autoincrement,
  2. name varchar(15), descr varchar(30))");
  3.     query.exec("create table IF NOT EXISTS lista (id integer primary key autoincrement,
  4. qta varchar(30), item INTEGER, FOREIGN KEY(item) REFERENCES items(id))");

main.cpp

  1. QLSqlTableModel *model = new QLSqlTableModel;
  2.     QLSqlTableModel *modelLista = new QLSqlTableModel;
  3.     model->setTable("items");
  4.     model->generateRoleNames();
  5.     model->select();
  6.     modelList->setTable("lists");
  7.     modelList->setRelation(2, QSqlRelation("items", "id", "name"));
  8.     modelList->select();
  9.     modelList->generateRoleNames();
  10.     QDeclarativeContext *ctxt = view.rootContext();
  11.     ctxt->setContextProperty("modelListItems", model);
  12.     ctxt->setContextProperty("modelList", modelLista);

In qml file

  1. Text {
  2.          id: name
  3.          text: model.name
  4.          font.bold: true; font.pointSize: 16
  5.          color: "white"
  6.  }
  7.  Text {
  8.           text: "Amount: " + model.qta
  9.           font.pointSize: 16
  10.           opacity: 1
  11.           color: "white"
  12.  }

——————————————————-
Edit:
Nice post, however the performance can be tweaked. data() will be called very often. Most of the processing and object instantiation should be done only once.

Categories: