从QML访问C ++模型

时间:2019-04-25 21:10:26

标签: c++ qt qml qt5

我创建了一个最小的工作示例。我希望这是可以理解的。我的问题是,我无法为顶级商品创建模型以进一步访问商品。这是类对象体系结构的样子:

CTop
    x times CMiddle
        y times CBottom

这是树结构。这是代码:

CBottom.h:

#ifndef CBOTTOM_H
#define CBOTTOM_H

#include <QObject>
#include <QtQml>

class CBottom : public QObject
{
    Q_OBJECT

    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)

public:

    CBottom(QObject *parent = nullptr) : QObject(parent)
    {

    }

    CBottom(const QString& name, QObject *parent = nullptr) : QObject(parent)
    {
        qmlRegisterType<CBottom>("Bottom", 1, 0, "Bottom");
        m_name = name;
    }

    QString name()
    {
        return m_name;
    }

    void setName(const QString& name)
    {
        if (name != m_name)
        {
            m_name = name;
            emit nameChanged();
        }
    }

signals:

    void nameChanged();

private:

    QString m_name;
};

#endif // CBOTTOM_H

CMiddle.h:

#ifndef CMIDDLE_H
#define CMIDDLE_H

#include <QObject>
#include <QtQml>
#include <QVector>

#include "cbottom.h"

class CMiddle : public QObject
{
    Q_OBJECT

    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)

public:

    CMiddle(QObject *parent = nullptr) : QObject(parent)
    {

    }

    CMiddle(const QString& name, const QStringList& bottoms, QObject *parent = nullptr) : QObject(parent)
    {
        qmlRegisterType<CMiddle>("Middle", 1, 0, "Middle");
        m_name = name;

        foreach (auto bottom, bottoms)
        {
            m_bottoms.append(new CBottom(bottom));
        }
    }

    QString name()
    {
        return m_name;
    }

    void setName(const QString& name)
    {
        if (name != m_name)
        {
            m_name = name;
            emit nameChanged();
        }
    }

signals:

    void nameChanged();

private:

    QString m_name;
    QVector<CBottom*> m_bottoms;
};

#endif // CMIDDLE_H

CTop.h:

#ifndef CTOP_H
#define CTOP_H

#include <QObject>
#include <QtQml>

#include "cmiddle.h"

class CTop : public QObject
{
    Q_OBJECT

public:

    CTop(QObject *parent = nullptr) : QObject(parent)
    {

    }

    CTop(const QStringList& middles, QObject *parent = nullptr) : QObject(parent)
    {
        qmlRegisterType<CTop>("Top", 1, 0, "Top");
        int i = 0;

        foreach (auto middle, middles)
        {
            QStringList bottoms;
            bottoms.append("A" + QString(i));
            bottoms.append("B" + QString(i));
            bottoms.append("C" + QString(i));
            i++;

            m_middles.append(new CMiddle(middle, bottoms));
        }
    }

    Q_INVOKABLE QVector<CMiddle*>& middles()
    {
        return m_middles;
    }

    Q_INVOKABLE CMiddle* middle(const int index)
    {
        return m_middles[index];
    }

private:

    QVector<CMiddle*> m_middles;

};

#endif // CTOP_H

main.c:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QString>
#include <QVector>
#include <QStringList>
#include <QVariant>
#include <QQmlContext>

#include "ctop.h"


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

    QGuiApplication app(argc, argv);

    QStringList middles;
    middles.append("FirstMiddle");
    middles.append("SecondMiddle");

    CTop* top = new CTop(middles);

    QQmlApplicationEngine engine;
    QQmlContext *ctxt = engine.rootContext();
    ctxt->setContextProperty("theTop", QVariant::fromValue(top));

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

main.qml:

import QtQuick 2.9
import QtQuick.Window 2.2

import Top 1.0

Window
{
    width: 600
    height: 400
    visible: true

    Repeater
    {
        model: theTop.middles();
        delegate: txtComp;
    }

    Component
    {
        id: txtComp;

        Text
        {
            text: name;
        }
    }

}

问题是:为什么QML代码中没有显示CMiddle对象之一的名称?我想从导出到QML的CMiddle组件中获取CTop组件(作为模型)。如果此代码有效,那么我将进一步研究并建立另一个模型来访问每个CBottom对象中的CMiddle对象。

例如,我注意到此QML代码有效:

import QtQuick 2.9
import QtQuick.Window 2.2

import Top 1.0

Window
{
    width: 600
    height: 400
    visible: true

    Repeater
    {
        model: theTop;
        delegate: txtComp;
    }

    Component
    {
        id: txtComp;

        Text
        {
            text: middle(0).name;
        }
    }

}

enter image description here

这没有多大意义,但表明CTop组件已正确暴露给QML部件。

为什么Qvector指针的输出CMiddle在QML部分中不能充当模型?

1 个答案:

答案 0 :(得分:1)

QML不知道QList<CMiddle *>,而应该使用QList<QObject *>

CTop.h

// ...
Q_INVOKABLE QList<QObject*> middles(){
    QList<QObject*> objects;
    for(CMiddle *m : qAsConst(m_middles)){
        objects << m;
    }
    return objects;
}
// ...

另一个错误是top不一定是指针,并且由于它是QVariant::fromValue(),因此可以不使用QObject来传递它:

main.cpp

// ...
CTop top(middles);
QQmlApplicationEngine engine;
QQmlContext *ctxt = engine.rootContext();
ctxt->setContextProperty("theTop", &top);

也可以在中继器中使用modelData获取模型的项目:

main.qml

//...
Component{
    id: txtComp;
    Text{
        text: modelData.name
    }
}
//...

可以找到完整的项目here