将SQLite与Qt Quick集成

10

我想在QT Quick中使用SQLite数据库,但找不到任何示例。我只是想能够从数据库中访问项目。是否有人知道我可以尝试的示例程序?

3个回答

9
你可以以QSqlQueryModel为例,或者使用其他SQL模型并将其添加到QML上下文中,在ListView中使用它。

创建模型

定义角色名称,委托将通过角色在QtQuick组件中访问数据(data方法有点天真,因为没有任何错误检查):

class SqlQueryModel: public QSqlQueryModel
{
    Q_OBJECT
    QHash<int,QByteArray> *hash;
public:
    explicit SqlQueryModel(QObject * parent) : QSqlQueryModel(parent)
    {
        hash = new QHash<int,QByteArray>;
        hash->insert(Qt::UserRole,      QByteArray("someRoleName"));
        hash->insert(Qt::UserRole + 1,  QByteArray("otherRoleName"));
    }
    QVariant data(const QModelIndex &index, int role) const
    {
       if(role < Qt::UserRole) {
          return QSqlQueryModel::data(index, role);
       }
       QSqlRecord r = record(index.row());
       return r.value(QString(hash->value(role))).toString();
    }
    inline RoleNameHash roleNames() const { return *hash; }
};

将其添加到QML中

创建新定义的模型类的实例并将其添加到QML上下文中。

view = new QQuickView();

QSqlQueryModel *someSqlModel = new SqlQueryModel(this);
someSqlModel->setQuery("SELECT someRoleName, otherRoleName FROM some_table");

QQmlContext *context = view->rootContext();
context->setContextProperty("someSqlModel", someSqlModel);

view->setSource(QUrl("qrc:///MainView.qml"));
view->show();

将模型绑定到QML视图

将您的模型绑定到ListView的model属性,并使用先前定义的角色名称来访问委托中的数据。

ListView {
    id: someListView
    model: someSqlModel
    delegate: Text {
        anchors.fill: parent
        text: someRoleName
    }
}

一些示例链接:

如何在QML中使用QSqlQueryModel

QML和QSqlTableModel


你的代码中没有任何“SqlQueryModel”的实例。声明SqlQueryModel类有什么意义? - Andrej Repiský
@ondrejandrej 这是一个笔误,我已经修正了,感谢您的注意。使用 QSqlQueryModel 使得定义 SqlQueryModel 没有意义,而且这个例子可能不会工作,因为 QML 找不到 someRoleName 角色。 - Davor Lucic

7

Rebus的回答是一个很好的开始,但我还想知道如何连接到现有的(SQLite)数据库。

所以这里是一个完整的例子,适用于Qt 5.x,不需要任何先决条件。

请注意,代码在SqlModel.data()中避免了角色名称哈希表查找和所有多余的堆分配。

主.cpp

#include <QtDebug>
#include <QString>
#include <QHash>
#include <QGuiApplication>
#include <QtQml>
#include <QQuickView>
#include <QtSql>
#include <QSqlQueryModel>

QSqlError initDb()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    // Open database file. The driver creates a new file if it doesn't exist yet.
    db.setDatabaseName("mylibrary.sqlite");
    if (!db.open())
        return db.lastError();

    QStringList tables = db.tables();
    if (tables.contains("books", Qt::CaseInsensitive)) {
        // DB has already been populated
        return QSqlError();
    }

    QSqlQuery query;
    if (!query.exec(QLatin1String("create table books(title varchar, author varchar)")))
        return query.lastError();
    if (!query.prepare(QLatin1String("insert into books(title, author) values(?, ?)")))
        return query.lastError();

    auto addBook = [&] (const QString& title, const QString& author) {
        query.addBindValue(title);
        query.addBindValue(author);
        query.exec();
    };

    addBook("Mademoiselle de Maupin", "T. Gautier");
    addBook("Der Nachsommer", "A. Stifter");
    addBook("L'Education sentimentale", "G. Flaubert");
    addBook("Voyna i mir", "L. Tolstoy");
    addBook("Mysterier", "K. Hamsun");
    addBook("The Sound and the Fury", "W. Faulkner");
    addBook("Tender is the Night", "F. Scott Fitzgerald");

    return QSqlError();
}

class SqlModel : public QSqlQueryModel
{
    Q_OBJECT

public:
    SqlModel(QObject* parent = 0)
        : QSqlQueryModel(parent)
    {
        roleNamesHash.insert(Qt::UserRole,      QByteArray("title"));
        roleNamesHash.insert(Qt::UserRole + 1,  QByteArray("author"));
    }

    QVariant data(const QModelIndex& index, int role) const
    {
        if(role < Qt::UserRole)
            return QSqlQueryModel::data(index, role);

        QSqlRecord r = record(index.row());
        return r.value(role - Qt::UserRole);
    }

    QHash<int, QByteArray> roleNames() const { return roleNamesHash; }

private:
    QHash<int, QByteArray> roleNamesHash;
};

int main(int argc, char **argv)
{
    QGuiApplication app(argc, argv);

    auto err = initDb();
    if (err.type() != QSqlError::NoError) {
        qCritical() << err.text();
        return 1;
    }

    SqlModel sqlModel;
    sqlModel.setQuery("SELECT title, author FROM books");

    QQuickView view;
    QQmlContext *context = view.rootContext();
    context->setContextProperty("sqlModel", &sqlModel);
    view.setResizeMode(QQuickView::SizeRootObjectToView);
    view.setSource(QUrl("qrc:///main.qml"));
    view.show();

    return app.exec();
}

#include "main.moc"

main.qml

import QtQuick 2.1

Item {
    width: 500
    height: 300

    ListView {
        anchors { fill: parent; margins: 20 }
        model: sqlModel
        delegate: Text {
            text: author + ' - ' + title
        }
    }
}

resources.qrc

<RCC>
    <qresource prefix="/">
        <file>main.qml</file>
    </qresource>
</RCC>

minimal-qml-sql-app.pro

CONFIG += c++11

QT += qml \
      quick \
      sql
SOURCES += main.cpp
OTHER_FILES += main.qml
RESOURCES += resources.qrc

我不得不删除Q_OBJECT和#include "main.moc"。不知道它们是否重要,但是除非我移除它们否则编译会失败。 - Mitch

4
在Qt 5.3中,有一个示例在

Examples/Qt-5.3/quick/controls/calendar

与Rebus和Kay的答案相比,有一个有趣的注释:日历示例使用

qmlRegisterType()

公开SqlModel。这允许更具声明性的编程风格:无需在main.cpp中实例化SqlModel,而是在qml中声明它。

非常好的入门点,可以以正确的方式学习使用QML进行SQL集成。非常感谢。 - NeoMorfeo
这是关于QML集成的一个好观点,但不幸的是,该示例中的模型并不真正像一个模型,因为Calendar已经有了自己的模型(用于月份中的天数)。相反,它只是获取特定日期的事件列表(QList<QObject*>模型)。由于这个事实,它最近被更改为简单地成为一个QObject:https://codereview.qt-project.org/#/c/145253/ - Mitch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接