Question

I'm trying to use a QDeclarativeListProperty in order to manage a list of parameters, mostly for the purposes of displaying them in a ListView. However, I would also like to be able to directly access the parameters in QML from the QDeclarativeListProperty so that I can display/modify individual parameters on different screens.

My class is called ParameterClass, for which I've created a QList:

class SystemData : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QDeclarativeListProperty<ParameterClass> parameters READ parameters CONSTANT)
    QDeclarativeListProperty<ParameterClass> parameters();

...

    QList<ParameterClass *> m_parameterList;
}

I've also registered the ParameterClass class and set up an instance of my SystemData as a property, which I know is necessary.

m_context->setContextProperty("SystemData", m_pSystemData);
qmlRegisterType<ParameterClass>();

Now, what I want to do within QML is something like this:

Rectangle {
    id: frame
    property variant parameter: SystemData.parameters[5]
    ...
}

I'm just not getting it to work: I keep getting back [undefined]. Am I wasting my time, or am I missing something?

Edit: I've changed things to use the suggestion from ... . Here are some selections from my updated code.

main.cpp:

#include <QApplication>
#include <QSplashScreen>
#include <QLocale>
#include <QLibraryInfo>
#include <QDeclarativeView>
#include <QDeclarativeContext>
#include <QDeclarativeEngine>
#include <QObject>
#include <QDeclarativeListProperty>

#include "systemdata.h"
#include "parameterclass.h"

static const QString contentPath = "qrc:/qml/qml/pk_ui/";
static const QString filename(contentPath + "main.qml");

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QDeclarativeView mainView;
    SystemData* systemData = SystemData::getInstance();

    QThread thread;
    UpdateWorker updateWorker;
    QObject::connect((const QObject*)systemData, SIGNAL(startWork()),
                     (const QObject*)&updateWorker, SLOT(doWork()));
    updateWorker.moveToThread(&thread);
    thread.start();
    systemData->startUpdates();

    QFont defaultFont;
    defaultFont.setFamily("Sans Serif");
    QApplication::setFont(defaultFont);

    // Register types to be available in QML
    qmlRegisterType<ParameterClass>();
    qmlRegisterUncreatableType<SystemEnum>("SystemEnums", 1, 0, "SystemEnum", QString());

    mainView.engine()->rootContext()->setContextProperty("SystemData", systemData);

    // Set view optimizations not already done for QDeclarativeView
    mainView.setResizeMode(QDeclarativeView::SizeRootObjectToView);
    mainView.setAttribute(Qt::WA_OpaquePaintEvent);
    mainView.setAttribute(Qt::WA_NoSystemBackground);

    mainView.setSource(QUrl(filename));
    mainView.show();

    return app.exec();
}

The ParameterClass looks like this:

class ParameterClass : public QObject
{
    Q_OBJECT

    Q_PROPERTY(int type READ get_type NOTIFY typeChanged)
    Q_PROPERTY(bool enabled READ get_ParameterEnabled WRITE set_ParameterEnabled NOTIFY enabledChanged)
    Q_PROPERTY(int groupID READ get_GroupID WRITE set_GroupID NOTIFY groupIDChanged)
    Q_PROPERTY(int unitID READ get_UnitID WRITE set_UnitID NOTIFY unitIDChanged)
    Q_PROPERTY(int securityLevel READ get_SecurityLevel WRITE set_SecurityLevel NOTIFY securityLevelChanged)
    Q_PROPERTY(QString parameterName READ get_ParameterName NOTIFY parameterNameChanged)
    Q_PROPERTY(QString shortDescription READ get_ShortDescription NOTIFY shortDescriptionChanged)
    Q_PROPERTY(int currentValue READ get_CV WRITE set_valueptrvalue NOTIFY currentValueChanged)
    Q_PROPERTY(int lowerBound READ get_LB NOTIFY lowerBoundChanged)
    Q_PROPERTY(int upperBound READ get_UB NOTIFY upperBoundChanged)

public:
    struct ValueTypes
    {
        enum
        {
            IntegerType,
            StringType,
            StringListType
        };
    };


    ParameterClass(QObject *parent = 0);
    int get_type();
    bool get_ParameterEnabled();
    int get_GroupID();
    int get_UnitID();
    int get_SecurityLevel();
    QString get_ParameterName();
    QString get_ShortDescription();
    int get_CV() { return *CurrentValuePtr; }
    int get_LB() { return *LowerBoundPtr; }
    int get_UB() { return *UpperBoundPtr; }

    void set_ParameterEnabled(bool InParameterEnabled);
    void set_GroupID(int InGroupID);
    void set_UnitID(int InUnitID);
    void set_SecurityLevel(int InSecurityLevel);

signals:
    void typeChanged();
    void enabledChanged();
    void groupIDChanged();
    void unitIDChanged();
    void securityLevelChanged();
    void parameterNameChanged();
    void shortDescriptionChanged();

private:
    int type;
    bool ParameterEnabled;
    int GroupID;
    int UnitID;
    int SecruityLevel;
    QString ParameterName;
    QString ShortDescription;
    int * CurrentValuePtr;
    int * LowerBoundPtr;
    int * UpperBoundPtr;
};

And my QML file:

Rectangle {
    id: frame
    property int val: SystemData.parameters[4].currentValue
    ...
}

It looks like I'm still getting an undefined value in this case. I'm trying to debug now, so that I can provide more information.

Was it helpful?

Solution

It's very much possible. The key is to make sure you register the QML type and set the context property before setting the source on your QDeclarativeView.

Here's a working example -

main.cpp:

#include <QApplication>
#include <QtDeclarative>

class MyPropertyObject : public QObject {
    Q_OBJECT
    Q_PROPERTY(int value READ value CONSTANT)

public:
    MyPropertyObject(int value = -1) : m_value(value) { }

    int value() const {
        return m_value;
    }

private:
    int m_value;
};

class MyObject : public QObject {
    Q_OBJECT
    Q_PROPERTY(QDeclarativeListProperty<MyPropertyObject> props READ props CONSTANT)

public:

    MyObject() {
        m_props.append(new MyPropertyObject(55));
        m_props.append(new MyPropertyObject(44));
        m_props.append(new MyPropertyObject(33));
    }

    QDeclarativeListProperty<MyPropertyObject> props() {
        return QDeclarativeListProperty<MyPropertyObject>(this, m_props);
    }

private:
    QList<MyPropertyObject *> m_props;
};

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

    QDeclarativeView view;
    view.engine()->rootContext()->setContextProperty(QLatin1String("tester"), new MyObject);
    qmlRegisterType<MyPropertyObject>();
    view.setSource(QUrl("qrc:///qml/main.qml"));
    view.setResizeMode(QDeclarativeView::SizeRootObjectToView);
    view.resize(300, 300);
    view.show();

    return a.exec();
}

#include "main.moc"

main.qml:

import QtQuick 1.1

Rectangle {
    property variant foo: tester.props[2].value

    Text {
        anchors.centerIn: parent
        text: parent.foo
    }
}

Note: read the docs for the QDeclarativeListProperty constructors. The one I'm using for this example is not the preferred one, but is good for quick prototypes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top