QML 组合框与 QSqlModel

QML Combobox with QSqlModel

我目前在用 QSqlTableModel 填充 QML Combobox 时遇到问题。

示例数据库:

  Table Customer                    Table Project
|   id   |   name   |      |   id   |   name  |  fk_customer  | 
|........|..........|      |........|.........|...............|
|    1   |  name1   |      |    1   |  pro1   |      1        |
|    2   |  name2   |      |    2   |  pro2   |      1        |
|    3   |  name3   |      |    3   |  pro3   |      3        |

我想按姓名向 select 客户显示带有 QML Combobox 的表格。
因此,我将组合框模型设置为 QSqlTableModeltable="customer"textRole="name".

我现在的问题在于将 Combobox.currentindex 设置为数据库中的正确值,当然还要从组合框中读回 selected ID
Comboboxes 文档指出,每当组合框填充新模型时,其当前索引设置为 1
我尝试使用组合框及其父项的 Component.onCompleted 信号设置当前索引,但 selected 索引始终设置为 1

所以我认为我在实施模型或 QML-file.

时可能犯了概念错误

有谁知道何时以及如何使用来自 C++ 模型的给定值预先设置 QML 组合框的建议方法?

我不明白问题是什么,因为你没有提供 MCVE,所以我的回复将尝试显示正确的解决方案。

假设您了解 QSqlTableModel 不能直接在 QML 中使用,但您必须添加与字段对应的角色并覆盖 data()roleNames() 方法。

要获取给定ID的信息,视图的currentIndex必须使用模型的data()方法,所以对应的QModelIndex和角色必须被创建,在这种情况下,为了简化该任务,我实现了一个函数,该函数给出了行和字段名称 returns 数据。

使用上面的方法我实现了以下class:

sqltablemodel.h

#ifndef SQLTABLEMODEL_H
#define SQLTABLEMODEL_H

#include <QSqlTableModel>
#include <QSqlRecord>

class SqlTableModel : public QSqlTableModel
{
    Q_OBJECT
    Q_PROPERTY(QStringList fieldNames READ fieldNames)
public:
    using QSqlTableModel::QSqlTableModel;
    QHash<int, QByteArray> roleNames() const
    {
       QHash<int, QByteArray> roles;
       for (int i = 0; i < record().count(); i ++) {
           roles.insert(Qt::UserRole + i + 1, record().fieldName(i).toUtf8());
       }
       return roles;
   }
    QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
    {
        QVariant value;
        if (index.isValid()) {
            if (role < Qt::UserRole) {
                value = QSqlQueryModel::data(index, role);
            } else {
                int columnIdx = role - Qt::UserRole - 1;
                QModelIndex modelIndex = this->index(index.row(), columnIdx);
                value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
            }
        }
        return value;
    }
    Q_INVOKABLE QVariant data(int row, const QString & fieldName){
        int col = record().indexOf(fieldName);
        if(col != -1 && 0 <= row && row < rowCount()){
            QModelIndex ix = index(row, col);
            return ix.data();
        }
        return QVariant();
    }
    QStringList fieldNames() const{
        QStringList names;
        for (int i = 0; i < record().count(); i ++) {
            names << record().fieldName(i);
        }
        return names;
    }
};

#endif // SQLTABLEMODEL_H

因此您必须创建模型并将其导出到 QML:

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);
    if(!createConnection()) // open the connection with the DB
        return -1;

    SqlTableModel model;
    model.setTable("Customer");
    model.select();

    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("cppmodel", &model);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

并在 QML 中建立连接:

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.4

Window {
    visible: true
    width: 320
    height: 240
    title: qsTr("ComboBox with SqlTableModel")
    ComboBox {
        anchors.centerIn: parent
        model: cppmodel
        textRole: "name"
        Component.onCompleted: currentIndex = 4
        onCurrentIndexChanged: {
            var id = cppmodel.data(currentIndex, "id");
            var name = cppmodel.data(currentIndex, "name");
            console.log(qsTr("currentIndex: %1, id: %2, name: %3").arg(currentIndex).arg(id).arg(name))
        }
    }
}

完整的示例可以在下面的 link 中找到。