简体   繁体   中英

How to access list property of C++ object in QML

I have started to learn the Qt 5 and got stuck at one point for a long time.

I have two classes. ScoreHandler handles a list of ScoreRecords. I create those two classes in C++ and set an instance of ScoreHandler as a context property. Now in QML I can assign the model, but the delegate can not see properties of ScoreRecord. Do I have to register something somewhere? Please help me.

scorerecord.h

class ScoreRecord : public QObject
{
    Q_OBJECT

    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(QString date READ date WRITE setDate NOTIFY dateChanged)
    Q_PROPERTY(QString score READ score WRITE setScore NOTIFY scoreChanged)
public:
    ScoreRecord(QObject *parent = 0);
    ScoreRecord(const QString& n, const QString &d, const QString &s, QObject *parent = 0);
    QString name() const;
    void setName(const QString &str);
    QString date() const;
    void setDate(const QString &str);
    QString score() const;
    void setScore(const QString &str);


signals:
    void nameChanged();
    void dateChanged();
    void scoreChanged();

public slots:

private:
    QString m_name;
    QString m_date;
    QString m_score;
};

scorehandler.h

class ScoreHandler : public QObject
{
    Q_OBJECT
private:
    const char* SCORE_TABLE_FILENAME;

    struct scoreRow {
        char name[128];
        char date[32];
        char score[16];
    };


public:
    explicit ScoreHandler(QObject *parent = 0);
    QList<ScoreRecord *> scoreList;

signals:

public slots:
    void SaveScore(const QString &name, const QString &date, const QString &score);
    void LoadScore();
};

main.c

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

    QGuiApplication app(argc, argv);
    QtQuick2ApplicationViewer viewer;

    ScoreHandler* scoreHandler = new ScoreHandler();
    QQmlContext* ctx = viewer.rootContext();
    ctx->setContextProperty("MyScoreModel", QVariant::fromValue(scoreHandler->scoreList));
    viewer.setMainQmlFile(QStringLiteral("qml/qmlListView/main.qml"));

    viewer.showExpanded();

    return app.exec();
}

QML file

import QtQuick 2.0

Rectangle {
    width: 360
    height: 360

    ListView {
        width: 100; height: 100
        anchors.fill: parent

        model: MyScoreModel
        delegate: Text {
            text: name
        }
    }
}

And please can somebody explain me, why the following code works? What is the reason?

main.c

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

    QGuiApplication app(argc, argv);
    QtQuick2ApplicationViewer viewer;

    ScoreHandler* scoreHandler = new ScoreHandler();
    QList<QObject *> scoreList;

    scoreList.append(new ScoreRecord("Jmeno1", "datum1", "score1"));
    scoreList.append(new ScoreRecord("Jmeno2", "datum2", "score2"));
    scoreList.append(new ScoreRecord("Jmeno3", "datum3", "score3"));

    QQmlContext* ctx = viewer.rootContext();
    ctx->setContextProperty("MyScoreModel", QVariant::fromValue(scoreList));
    viewer.setMainQmlFile(QStringLiteral("qml/qmlListView/main.qml"));

    viewer.showExpanded();

    return app.exec();
}

I believe there is a cleaner way of doing it. You need to define a property scoreList on your ScoreHandler:

Q_PROPERTY(QQmlListProperty<ScoreRecord> scoreList READ scoreList)

And a private variable that holds your ScoreRecord pointers:

QList _scoreRecords;

Then you need to implement the accessor method:

// ScoreHandler.h
QQmlListProperty<ScoreRecord> scoreList();

// ScoreHandler.cpp
QQmlListProperty<ScoreRecord> ScoreHandler::scoreList()
{
    return QQmlListProperty<ScoreRecord>(this, _scoreRecords);
}

You can then access it from qml.

There is an example on QtCreator about this. It is called Extending QML - Object and List Property Types Example

I strongly believe that

ctx->setContextProperty("MyScoreModel", QVariant::fromValue(scoreHandler->scoreList));

performs a copy of your current list, which is empty in the example given, and is not updated when you modify scoreList . Qt doc says:

Note: There is no way for the view to know that the contents of a QList has changed. If the QList changes, it is necessary to reset the model by calling QQmlContext::setContextProperty() again.

If you need real data model, derive from QAbstractListModel and implement necessary overrides: data(...) , rowCount() and count property, roleNames() .

The last sample works because it assigns static list to context variable. Same as in JavaScript:

[{name: Jmeno1, date: datum1, score: score1},
{name: Jmeno2, date: datum3, score: score2},
{name: Jmeno3, date: datum3, score: score3}]

Nuno Santos answer is good, I would also point two important modifications you may need:

Note that ScoreRecord must be registered with the QML type system, eg.: qmlRegisterType<ScoreRecord>("com.mycompany.database", 1, 0, "ScoreRecord");

and if ScoreRecord is in namespace, you have to define property like this:

Q_PROPERTY(QQmlListProperty<myNamespace::ScoreRecord> scoreList READ scoreList)

请注意,如果ScoreRecord在命名空间中,您可能必须像这样声明 Q_PROPERTY。

Q_PROPERTY(QQmlListProperty<myNamespace::ScoreRecord> scoreList READ scoreList)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM