【问题标题】:Integrating SQLite with Qt Quick将 SQLite 与 Qt Quick 集成
【发布时间】:2023-06-06 19:38:02
【问题描述】:

我正在尝试在 QT Quick 中包含一个 SQLite 数据库,但我找不到任何示例。我只想能够访问数据库中的项目。有谁知道我可以玩的任何示例程序吗?

【问题讨论】:

    标签: sqlite qml qt-quick


    【解决方案1】:

    例如,您可以采用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 视图

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

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

    一些示例链接:

    How to use a QSqlQueryModel in QML

    QML and QSqlTableModel

    【讨论】:

    • 您的代码中没有任何“SqlQueryModel”实例。声明类 SqlQueryModel 有什么意义?
    • @ondrejandrej 这是一个错字,我已经修正了,感谢您的注意。使用QSqlQueryModel 使定义SqlQueryModel 毫无意义,并且该示例可能不起作用,因为QML 找不到someRoleName 角色。
    【解决方案2】:

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

    这里有一个完整的 Qt 5.x 示例,不需要任何先决条件。

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

    ma​​in.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"
    

    ma​​in.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"。不知道这些是否重要,但除非我删除它们,否则它不会构建。
    【解决方案3】:

    在 Qt 5.3 中,

    中有一个示例

    示例/Qt-5.3/quick/controls/日历

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

    公开 SqlModel

    qmlRegisterType()

    这允许一种更具声明性的编程风格:无需在 main.cpp 中实例化 SqlModel。相反,你在你的 qml.xml 中声明它。

    【讨论】:

    • 以正确的方式使用 QML 学习 SQL 集成的绝佳切入点。非常感谢
    • 这是关于 QML 集成的一个好点,但不幸的是,该示例中的模型实际上并不像模型,因为 Calendar 已经有自己的模型(一个月中的几天)。相反,它只获取特定日期的事件列表(QList&lt;QObject*&gt; 模型)。由于这个事实,它最近被简单地更改为QObjectcodereview.qt-project.org/#/c/145253