【问题标题】:QSqlTableModel to qml list coming through multiple timesQSqlTableModel 到 qml 列表多次出现
【发布时间】:2020-01-22 09:07:37
【问题描述】:

我是新手,正在尝试学习 qt 和 qml,但我找不到解决此问题的方法。

我有一个只有 4 行测试数据的 QSqlTableModel,但我想将 1 列(其中只有 1 个值)中的不同值转换为 qml ListModel 的列表。

我的 SqlDataModel.h 文件中有这个 Q_PROPERTY(QStringList distinctSemesters READ getSemesterList NOTIFY semesterChanged),我的 sqldatamodel.cpp 中有这个

QStringList  SqlDataModel::getSemesterList() const
{
    QStringList  mySemesters;
    QSqlQuery query;
    query.exec("SELECT DISTINCT Semester FROM results");
    while (query.next()) {
        QString currentSemester = query.value(0).toString();
        mySemesters << currentSemester;
    }
    return mySemesters;
}

它返回一个长度为 1 的 QStringList。我正在尝试使用

将其读入我的 qml
ListView {
    model: SqlDataModel {
                    id: myModel
                }
    delegate: ItemDelegate {
                width: parent.width
                text: myModel.distinctSemesters
            }
}

这适用于从 getSemesterList() 函数获取字符串。但是字符串在列表视图中重复了 4 次(我的表模型的大小)。我已经检查了这一点并在测试表中添加了更多行,这会在我的列表视图中继续重复相同的字符串更多次。

根据我有限的理解,我猜这将永远是这种情况,因为列表视图从模型中获取它的大小 - 这是 qsl 表的大小。我不知道该怎么做,其他人可以指出我正确的方向吗?

我目前的想法是创建一个新的 sqlmodel 以引入 qml(但我需要读+写,所以我相信 sqltablemodel 对此有好处),或者我应该尝试使用 javascript 修复 qml 方面。我在 javascript 中查看了它,但是当我尝试时

property ListModel distinctSemesters;
Component.onCompleted: {
              console.log(distinctSemesters)

我不断收到关于 distinctSemesters 未定义的错误。

非常感谢您的帮助。

下面(我希望)是一个可重现的例子。我使用了一些在线资源来指导这一点。 main.cpp:

int main(int argc, char *argv[])
{
    initDatabase();

    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QApplication app(argc, argv);

    qmlRegisterType<SqlDataModel>("GradesSqlDataModel", 1, 0, "SqlDataModel");


    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

SqlDataModel.h

class SqlDataModel : public QSqlTableModel
{
    Q_OBJECT
    Q_PROPERTY(QString semester READ getsemester WRITE setSemester NOTIFY semesterChanged)
    Q_PROPERTY(QStringList distinctSemesters READ getSemesterList NOTIFY semesterChanged)

public:
    SqlDataModel(QObject *parent = 0);

    QStringList getSemesterList() const;
    QString getsemester() const;

    QVariant data(const QModelIndex &index, int role) const override;
    QHash<int, QByteArray> roleNames() const override;

signals:
    void semesterChanged();
};

SqlDataModel.cpp

SqlDataModel::SqlDataModel(QObject *parent) :
    QSqlTableModel(parent)
{
    createTable();
    setTable("Results");
    setEditStrategy(QSqlTableModel::OnManualSubmit);
    select();

}

QStringList  SqlDataModel::getSemesterList() const
{
    QStringList  mySemesters;
    QSqlQuery query;
    query.exec("SELECT DISTINCT Semester FROM results");
    while (query.next()) {
        QString currentSemester = query.value(0).toString();
        mySemesters << currentSemester;
        qDebug() << currentSemester;
    }
    qDebug() << "length :" <<mySemesters.length();
    return mySemesters;
}

QHash<int, QByteArray> SqlDataModel::roleNames() const
{
    QHash<int, QByteArray> dataNames;
    dataNames[Qt::UserRole] = "ID";
    dataNames[Qt::UserRole + 1] = "Semester";
    dataNames[Qt::UserRole + 2] = "CourseTitle";
    dataNames[Qt::UserRole + 3] = "TestWeight";
    dataNames[Qt::UserRole + 4] = "TestName";
    dataNames[Qt::UserRole + 5] = "Result";
    dataNames[Qt::UserRole + 6] = "OutOf";
    qDebug() << "DataNames" << dataNames;
    return dataNames;
}
QVariant SqlDataModel::data(const QModelIndex &index, int role) const
{
    qDebug() << "settingData";
    if (role < Qt::UserRole)
        return QSqlTableModel::data(index, role);

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

main.qml

ApplicationWindow {
    id: window;
    visible: true;
    width: 640;
    height: 600;
    title: qsTr("TEST")

    Drawer {
        id: drawer
        width: Math.min(window.width, window.height) / 3 * 2
        height: window.height
        interactive: true

        ListView {
                  model: SqlDataModel {
                    id: myModel
                }
                delegate: ItemDelegate {
                         width: parent.width
                         text: myModel.distinctSemesters
               }
       }
}   

我的结果 sql 表看起来像这样(只有 ID 主键在前):

query.exec("INSERT INTO results (Semester, CourseTitle, TestWeight, TestName, Result, OutOf) VALUES ('Spring 2020', 'Course 1', '10', 'Exam 1', 50, 100)");
    query.exec("INSERT INTO results (Semester, CourseTitle, TestWeight, TestName, Result, OutOf) VALUES ('Spring 2020', 'Course 1', '33', 'Exam 2', 70, 100)");
    query.exec("INSERT INTO results (Semester, CourseTitle, TestWeight, TestName, Result, OutOf) VALUES ('Spring 2020', 'Course 2', '25', 'Exam 1', 0, 100)");
    query.exec("INSERT INTO results (Semester, CourseTitle, TestWeight, TestName, Result, OutOf) VALUES ('Spring 2020', 'Course 2', '5', 'Quiz 1', 5, 20)");

【问题讨论】:

  • 在while之后你是否也观察到重复的元素:while(query.next())){...}qDebug() &lt;&lt; mySemesters;
  • 是的,我愿意。我不知道要给出多少示例,有机会我会尝试将其他代码放在一起

标签: c++ qt qml


【解决方案1】:

说明:

在您的情况下,QSqlTableModel 加载表的所有行,因为没有过滤器,因此它将有 4 行,因此使用它的任何视图也将显示这 4 行,因此 ListView 显示 4 行。为什么每一行都显示相同的信息?好吧,因为在每个项目中,您都有代表显示始终是“2020 年春季”的不同“学期”。

解决方案:

在这种情况下,没有必要使用 QSqlTableModel,因为 QSqlQueryModel 足以允许从 QML 进行过滤,因此您可以使用 my other answer 的模型。因此,只需将其放在导出到 QML 并使用它就足够了。

qmlRegisterType<SqlQueryModel>("GradesSqlDataModel", 1, 0, "SqlQueryModel");
import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick.Controls 2.14
import GradesSqlDataModel 1.0

Window {
    id: window
    visible: true
    width: 640;
    height: 600;

    SqlQueryModel{
        id: sqlquerymodel
        query: "SELECT DISTINCT Semester FROM results"
    }
    Drawer {
        id: drawer
        width: Math.min(window.width, window.height) / 3 * 2
        height: window.height
        interactive: true
        ListView{
            anchors.fill: parent
            model: sqlquerymodel
            delegate: ItemDelegate {
                width: parent.width
                text: model.Semester
            }
        }
    }
    Component.onCompleted: drawer.visible = true
}

完整示例可以在here 找到。

【讨论】:

  • 非常感谢!这完全有道理。我查看了 QSqlQueryModel,但从我可以看到 QSqlQueryModel 是只读的,我希望能够在我的应用程序的其他区域中编写(并希望更新此列表)?或者我可以在查询中使用 SQL 语言直接写入数据库吗?
  • @AdamLaird QSqlTableModel 不是唯一的编写方式,因为您似乎知道可以使用 QSqlQuery。在您的要求中,您没有指明任何内容,因此我将在回答中忽略它。如果您有新问题,请按照 SO 规则创建一个新帖子。
  • 对不起,我应该在问题中更清楚地说明我也需要它来写(虽然它在原始问题中)。不过感谢您的帮助,我不知道我可以在 QSqlQueryModel 中编写代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多