简体   繁体   中英

Qt / QML set property from c++ class for GridView

First i created a new c++ class with a member function, which is giving back a string:

#ifndef TESTNAME_H
#define TESTNAME_H

#include <QObject>
#include <QString>
#include <QVariant>


class testname : public QObject
{

    Q_OBJECT;

public:
    testname();
    Q_INVOKABLE QString getName();
};

#endif // TESTNAME_H


#include "testname.h"

testname::testname()
{
}


QString testname::getName() {

    return "sometext";
}

I have a qml file with only a text in the middle, like this:

import QtQuick 1.1

Rectangle {
    width: 360
    height: 360

    Text {
        id: text1
        anchors.centerIn: parent
        text: testqml
        font.pixelSize: 12
    }
}

Notice that the property "text" is a variable named "testqml". This variable contains the string returned by the function of the class i showed above. The code for this is in the main.cpp:

#include <QApplication>
#include "qmlapplicationviewer.h"
#include <testname.h>
#include <QDeclarativeContext>
#include <QDebug>

Q_DECL_EXPORT int main(int argc, char *argv[])
{
    QScopedPointer<QApplication> app(createApplication(argc, argv));


    // Create instance of "testname"
    testname *test = new testname;

    QmlApplicationViewer viewer;

    viewer.rootContext()->setContextProperty("testqml", test->getName());

    viewer.addImportPath(QLatin1String("modules"));
    viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
    viewer.setMainQmlFile(QLatin1String("qml/classtest/main.qml"));
    viewer.showExpanded();

    return app->exec();
}

Using the setContextProperty-Function, the returned string is exposed to the qml file and is correctly shown in the running program. But i'm actually intending to inherit a model for a GridView. So i created a Gridview with one list element in QML:

import QtQuick 1.1

Rectangle {
    width: 360
    height: 360

    GridView {
        id: grid_view1
        anchors.centerIn: parent
        width: 140
        height: 140
        cellHeight: 70
        delegate: Item {
            x: 5
            height: 50
            Column {
                spacing: 5
                Rectangle {
                    width: 40
                    height: 40
                    color: colorCode
                    anchors.horizontalCenter: parent.horizontalCenter
                }

                Text {
                    x: 5
                    text: name
                    anchors.horizontalCenter: parent.horizontalCenter
                    font.bold: true
                }
            }
        }
        model: ListModel {

            ListElement {
                name: testqml
                colorCode: "grey"
            }


        }
        cellWidth: 70
    }
}

The variable "testqml" is now in the "name" Field of the List, which is in the example a string. If i use a string "likethis", it is correctly displayed. But if i run my program (main.cpp and class are remaining unchanged) i get this error:

ListElement: cannot use script for property value 
                     name: testqml 
                     ^ 

Now i'm stuck. I found an reported bug with a similar issue #QTBUG-16289 , but i don't know how to solve my problem. Any ideas, how-tos, tutorials or something to solve my problem?

Thanks and regards :)

I ran your code and reproduced your error but what are you ultimately trying to do?

Your delegate indicates that you want to inject a number of model items with name and color from C++, otherwise, why use a GridView , correct?

If that is not the case then perhaps what follows will not be that useful, or perhaps some variant of it might be. So I went ahead and constructed an example of what I thought you might be trying to accomplish.

In summary, on my system, after creating an arbitrary number of model items (in this case 20), the scrollable GridView delegate (midway along the scroll range) looks like this:

在此输入图像描述

As I said, it seems that you want to inject a number of QString items from a C++ model into a QML GridView , noting that using a GridView implies that you would like to have a number of items. In most cases you will want to inherit from a pre-defined Qt Model, which automatically takes care of several important details like keeping the QML views in-sync with the model, and automatically updating the views when items are removed or new ones are added.

With this in mind, the QAbstractListModel is a convenient Class from which to base your model (this is not the only option though, see the help files). At first glance, setting up this model can appear complicated, so I went ahead and defined a minimal version which I hope illustrates what you want to do.

Below is the code for the model (note: I put all of the code in the .h file so no .m file is needed). I also created some "Items" to inject into the model, for simplicity, a struct Item is used as defined below, but these could easily be instances of another suitably defined Class:

#include <QString>
#include <QColor>
#include <QDebug>
#include <QAbstractListModel>

// Create an Item so we have something to put in the model:
struct Item {
    QString name;
    QString color;
};

class testname : public QAbstractListModel
{
    Q_OBJECT

public:
    explicit testname(QObject *parent = 0) : QAbstractListModel(parent)
    {
        // Create some items and then add to the model:
        int N = 20;
        QStringList colorNames = QColor::colorNames();
        Item* items = new Item[N];
        for (int i = 0; i < N; i++) {
            items[i].name = QString("item"+QString::number(i));
            items[i].color = colorNames[i];
            //qDebug() << items[i].name << "; " << items[i].color;
            _model<<items[i];
        }
    }

    // enum DataRoles for QAbstractListModel:
    enum DataRoles {
        NameRole = Qt::UserRole + 1,
        ColorRole
    };

    // addData() method for QAbstractListModel:
    void addData(const Item& entry) {
        beginInsertRows(QModelIndex(), rowCount(), rowCount());
        _model << entry;
        endInsertRows();
    }

    // rowCount() method for QAbstractListModel:
    int rowCount(const QModelIndex & parent = QModelIndex()) const {
        return _model.count();
    }

    // data() required for QAbstractListModel:
    QVariant data(const QModelIndex & index, int role) const {
        if ( !index.isValid() || index.row() < 0 || index.row() >= _model.count() )
            return QVariant();
        Item modelEntry = _model[index.row()];
        if (role == NameRole) {return modelEntry.name;}
        if (role == ColorRole) {return modelEntry.color;}
        return QVariant();
    }

    // roleNames() method for QAbstractListModel:
    QHash<int,QByteArray> roleNames() const {
        QHash<int, QByteArray> roles;
        roles[NameRole] = "Name";
        roles[ColorRole] = "Color";
        return roles;
    }

private:
    // Below are the model items:
    QList<Item> _model;

};

Next is the QML code which uses the C++ model defined above and registered as "testqml" in main.cpp, and then defined through the property, model: in GridView .

Note that in the delegate that the Color and Name properties of the model are defined as role names in the class above (these could be any label you like). To help visualize what is going on, the model roles are very similar to the columns of a table, with the row entries corresponding to the model items:

import QtQuick 1.1

Rectangle {
    width: 360
    height: 360
    /* ------------------- */
    GridView {
        id: grid_view1
        anchors.centerIn: parent
        width: 140; height: 140
        cellHeight: 70
        delegate: delegateItem
        model: testqml // the C++ model is set here
        cellWidth: 70;
    }
    /* ------------------- */
    Component {
        id: delegateItem
        Item {
            x: 5; height: 50
            Column {
                spacing: 5
                Rectangle {
                    width: 40; height: 40;
                    color: Color // Note: this a role defined in the C++ model
                    anchors.horizontalCenter: parent.horizontalCenter
                }
                Text {
                    x: 5;
                    text: Name // Note: this is another role defined in the C++ model
                    anchors.horizontalCenter: parent.horizontalCenter
                    font.bold: true
                }
            }
        }
    } // end delegateItem

} // end Rectangle

And then my main.cpp is nearly the same as yours, I'll go ahead and post it to avoid any confusion:

#include "qtquick1applicationviewer.h"
#include <QApplication>
#include "testname.h"
#include <QDeclarativeContext>

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

    testname *test = new testname();
    QtQuick1ApplicationViewer viewer;
    viewer.rootContext()->setContextProperty("testqml",test);

    viewer.addImportPath(QLatin1String("modules"));
    viewer.setOrientation(QtQuick1ApplicationViewer::ScreenOrientationAuto);
    viewer.setMainQmlFile(QLatin1String("qml/QMLSetProperty/main.qml"));
    viewer.showExpanded();

    return app.exec();
}

Hope this helps!

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