QML and QSqlTableModel: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
(Convert ExpressionEngine links)
No edit summary
 
(9 intermediate revisions by 7 users not shown)
Line 1: Line 1:
{{Cleanup | reason=Auto-imported from ExpressionEngine.}}
{{Cleanup | reason=Auto-imported from ExpressionEngine.}}
 
[[Category:Snippets::QML]]
[[Category:snippets]]
[[Category:Tutorial]]
[[Category:Developing_with_Qt::Qt Quick::Tutorial]]
[[Category:Developing with Qt::Qt Quick::QML]]
 
{{LangSwitch}}
= 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.
I wrote a simple class derived from QSqlRelationalTableModel to facilitate the use of such classes with QML, without manually defining the roles.
Line 11: Line 10:


<code>
<code>
class QLSqlTableModel : public QSqlRelationalTableModel
class QLSqlTableModel : public QSqlRelationalTableModel
{
{
Q_OBJECT
    Q_OBJECT
 
private:
private:
QHash<int, QByteArray> roles;
    QHash<int, QByteArray> roles;


public:
public:
QLSqlTableModel(QObject *parent = 0);
    QLSqlTableModel(QObject *parent = 0);
~QLSqlTableModel();
    ~QLSqlTableModel();
Q_INVOKABLE QVariant data(const QModelIndex &amp;index, int role=Qt::DisplayRole ) const;
 
void generateRoleNames();
public:
    Q_INVOKABLE QVariant data(const QModelIndex &index, int role=Qt::DisplayRole ) const;
    void generateRoleNames();
 
#ifdef HAVE_QT5
#ifdef HAVE_QT5
virtual QHash<int, QByteArray> roleNames() const{return roles;}
    virtual QHash<int, QByteArray> roleNames() const{return roles;}
#endif
#endif
}
}


QVariant QLSqlTableModel::data ( const QModelIndex &amp; index, int role ) const
QVariant QLSqlTableModel::data ( const QModelIndex & index, int role ) const
{
{
if(index.row() >= rowCount())
    if(index.row() >= rowCount())
return QString("");
    {
}
        return QString("");
if(role < Qt::UserRole)
    }
{
    if(role < Qt::UserRole)
return QSqlQueryModel::data(index, role);
    {
}
        return QSqlQueryModel::data(index, role);
else {
    }  
// search for relationships
    else  
for (int i = 0; i < columnCount(); i+'') {
    {
if (this->relation(i).isValid()) {
        // search for relationships
return record(index.row()).value(QString(roles.value(role)));
        for (int i = 0; i < columnCount(); ++i)  
}
        {
}
            if (this->relation(i).isValid())  
// if no valid relationship was found
            {
return QSqlQueryModel::data(this->index(index.row(), role - Qt::UserRole - 1), Qt::DisplayRole);
            return record(index.row()).value(QString(roles.value(role)));
}
            }
 
        }
    // if no valid relationship was found
    return QSqlQueryModel::data(this->index(index.row(), role - Qt::UserRole - 1), Qt::DisplayRole);
    }
}
</code>
</code>


Line 55: Line 61:
void QLSqlTableModel::generateRoleNames()
void QLSqlTableModel::generateRoleNames()
{
{
roles.clear();
    roles.clear();
int nbCols = this->columnCount();
    int nbCols = this->columnCount();
for (int i = 0; i < nbCols; i) {
roles[Qt::UserRole'' i + 1] = QVariant(this->headerData(i, Qt::Horizontal).toString()).toByteArray();


}
    for (int i = 0; i < nbCols; ++i)
    {
        roles[Qt::UserRole + i + 1] = QVariant(this->headerData(i, Qt::Horizontal).toString()).toByteArray();
    }
#ifndef HAVE_QT5
#ifndef HAVE_QT5
setRoleNames(roles);
    setRoleNames(roles);
#endif
#endif
}
}
</code>
</code>


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


Example:
=== Example: ===


Tables:
Tables:
Line 76: Line 82:
<code>
<code>
query.exec("create table IF NOT EXISTS items (id integer primary key autoincrement,
query.exec("create table IF NOT EXISTS items (id integer primary key autoincrement,
name varchar(15), descr varchar(30))");
            name varchar(15), descr varchar(30))");
query.exec("create table IF NOT EXISTS lista (id integer primary key autoincrement,
query.exec("create table IF NOT EXISTS lista (id integer primary key autoincrement,
qta varchar(30), item INTEGER, FOREIGN KEY (item) REFERENCES items(id))");
            qta varchar(30), item INTEGER, FOREIGN KEY (item) REFERENCES items(id))");
</code>
</code>


Line 85: Line 91:
<code>
<code>
QLSqlTableModel *model = new QLSqlTableModel;
QLSqlTableModel *model = new QLSqlTableModel;
QLSqlTableModel *modelLista = new QLSqlTableModel;
QLSqlTableModel *modelLista = new QLSqlTableModel;
model->setTable("items");
 
model->generateRoleNames();
model->setTable("items");
model->select();
model->generateRoleNames();
modelList->setTable("lists");
model->select();
modelList->setRelation(2, QSqlRelation("items", "id", "name"));
 
modelList->select();
modelLista->setTable("lists");
modelList->generateRoleNames();
modelLista->setRelation(2, QSqlRelation("items", "id", "name"));
QDeclarativeContext *ctxt = view.rootContext();
modelLista->select();
ctxt->setContextProperty("modelListItems", model);
modelLista->generateRoleNames();
ctxt->setContextProperty("modelList", modelLista);


QDeclarativeContext *ctxt = view.rootContext();
ctxt->setContextProperty("modelListItems", model);
ctxt->setContextProperty("modelList", modelLista);
</code>
</code>


Line 102: Line 110:
<code>
<code>
Text {
Text {
id: name
    id: name
text: model.name
    text: model.name
font.bold: true; font.pointSize: 16
    font.bold: true; font.pointSize: 16
color: "white"
    color: "white"
}
}
Text {
 
text: "Amount: " + model.qta
Text {
font.pointSize: 16
    text: "Amount: " + model.qta
opacity: 1
    font.pointSize: 16
color: "white"
    opacity: 1
}
    color: "white"
}
</code>
</code>



Latest revision as of 18:51, 24 July 2021

This article may require cleanup to meet the Qt Wiki's quality standards. Reason: Auto-imported from ExpressionEngine.
Please improve this article if you can. Remove the {{cleanup}} tag and add this page to Updated pages list after it's clean.

En Ar Bg De El Es Fa Fi Fr Hi Hu It Ja Kn Ko Ms Nl Pl Pt Ru Sq Th Tr Uk Zh

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

If you want to understand why roles are so important when working with SQL table models and QML, have a look at this explained code snippet

class QLSqlTableModel : public QSqlRelationalTableModel
{
    Q_OBJECT

private:
    QHash<int, QByteArray> roles;

public:
    QLSqlTableModel(QObject *parent = 0);
    ~QLSqlTableModel();

public:
    Q_INVOKABLE QVariant data(const QModelIndex &index, int role=Qt::DisplayRole ) const;
    void generateRoleNames();

#ifdef HAVE_QT5
    virtual QHash<int, QByteArray> roleNames() const{return roles;}
#endif
}

QVariant QLSqlTableModel::data ( const QModelIndex & index, int role ) const
{
    if(index.row() >= rowCount())
    {
        return QString("");
    }
    if(role < Qt::UserRole)
    {
        return QSqlQueryModel::data(index, role);
    } 
    else 
    {
        // search for relationships
        for (int i = 0; i < columnCount(); ++i) 
        {
            if (this->relation(i).isValid()) 
            {
            return record(index.row()).value(QString(roles.value(role)));
            }
        }
    // if no valid relationship was found
    return QSqlQueryModel::data(this->index(index.row(), role - Qt::UserRole - 1), Qt::DisplayRole);
    }
}

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 and not QVariant value, in order to have a correct visualization in QML.

void QLSqlTableModel::generateRoleNames()
{
    roles.clear();
    int nbCols = this->columnCount();

    for (int i = 0; i < nbCols; ++i) 
    {
        roles[Qt::UserRole + i + 1] = QVariant(this->headerData(i, Qt::Horizontal).toString()).toByteArray();
    }
#ifndef HAVE_QT5
    setRoleNames(roles);
#endif
}

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

Example:

Tables:

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

main.cpp

QLSqlTableModel *model = new QLSqlTableModel;
QLSqlTableModel *modelLista = new QLSqlTableModel;

model->setTable("items");
model->generateRoleNames();
model->select();

modelLista->setTable("lists");
modelLista->setRelation(2, QSqlRelation("items", "id", "name"));
modelLista->select();
modelLista->generateRoleNames();

QDeclarativeContext *ctxt = view.rootContext();
ctxt->setContextProperty("modelListItems", model);
ctxt->setContextProperty("modelList", modelLista);

In qml file

Text {
    id: name
    text: model.name
    font.bold: true; font.pointSize: 16
    color: "white"
}

Text {
    text: "Amount: " + model.qta
    font.pointSize: 16
    opacity: 1
    color: "white"
}



Note1: 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.

Note2: I modified provided code according to this working example which was based on this wiki page