returning objects from roles



  • Hey,

    I'm trying to get a role to return an object. I'm running into undefined errors when I try to access display.blockNumber and display.time

    here's my code

    blockdisplay.h:

    #ifndef BLOCKDISPLAY_H
    #define BLOCKDISPLAY_H
    
    #include <QMetaType>
    
    class BlockDisplay
    {
    public:
        BlockDisplay();
        BlockDisplay(int blocknum, long time);
        BlockDisplay(const BlockDisplay &other);
    
        int blockNumber() const;
        long time() const;
    
    private:
        int m_blocknumber;
        long m_time;
    };
    
    Q_DECLARE_METATYPE(BlockDisplay)
    
    #endif // BLOCKDISPLAY_H
    

    blockdisplay.cpp:

    #include "blockdisplay.h"
    
    
    BlockDisplay::BlockDisplay() {
    
    }
    
    BlockDisplay::BlockDisplay(int blocknum, long time) {
        this->m_blocknumber = blocknum;
        this->m_time = time;
    }
    
    BlockDisplay::BlockDisplay(const BlockDisplay &other) {
        this->m_blocknumber = other.blockNumber();
        this->m_time = other.time();
    }
    
    
    int BlockDisplay::blockNumber() const {
        return this->m_blocknumber;
    }
    
    long BlockDisplay::time() const {
        return this->m_time;
    }
    

    modelclass.h:

    #ifndef MODELCLASS_H
    #define MODELCLASS_H
    
    #include <QObject>
    #include <QAbstractListModel>
    #include <QStringListModel>
    
    #include <blockchain.h>
    
    class ModelClass : public QAbstractListModel
    {
        Q_OBJECT
    
        Q_PROPERTY(qint32 blockheight READ blockheight)
    
    protected:
        Blockchain bc{};
        int first;
    public:
        ModelClass();
        qint32 blockheight();
        void init();
    
        int rowCount(const QModelIndex &parent = QModelIndex()) const;
        QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
    };
    
    #endif // MODELCLASS_H
    

    modelclass.cpp:

    #include "modelclass.h"
    
    #include <string.h>
    #include <qdebug>
    
    #include "blockdisplay.h"
    
    using namespace std;
    
    ModelClass::ModelClass()
    {
    
    }
    
    void ModelClass::init() {
        bc.init();
        if ( !bc.Valid() )
            qDebug() << "invalid";
        else {
            bc.SeekToFirst();
            bc.Next();
            if ( !bc.Valid() )
                qDebug() << "invalid";
            else
                first = bc.GetCurrentBlock().signedhead().head().num();
        }
    
        //setProperty("blockheight",bc.GetBlockHeight());
    }
    
    qint32 ModelClass::blockheight() {
        return bc.GetBlockHeight();
    }
    
    int ModelClass::rowCount(const QModelIndex &parent) const {
        //qInfo() << " 0test " << bc.GetBlockHeight();
    
        return bc.GetBlockHeight() - first;
    }
    
    QVariant ModelClass::data(const QModelIndex & index, int role) const {
        qInfo() << " 1test " << index;
        int row = bc.GetBlockHeight() - index.row();// + 1 + first;
        if (index.isValid()) {
    
            bc.Seek(row);
    
            if (bc.Valid()) {
                if (role == Qt::DisplayRole) {
                    int blocknum = bc.GetCurrentBlock().signedhead().head().num();
                    long timestamp = bc.GetCurrentBlock().signedhead().head().timestamp();
    
                    BlockDisplay dsply{blocknum, timestamp};
                    QVariant var;
                    var.setValue(dsply);
                    return var;
                }
            }
        }
    
        return QVariant();
    }
    

    snippet from blocks.qml:

        Component {
            id: gridComp
            Row {
                Text {
                    text: display.blockNumber + " "
    
                    MouseArea {
                        anchors.fill: parent
                        onClicked: {
                            list.currentIndex = index;
                            ld.setSource("detail.qml")
                        }
                    }
                }
                Text {
                    text: display.time + " "
                }
            }
        }
    

    [edit: fixed missing coding tags SGaist]


  • Lifetime Qt Champion

    Hi,

    You should take a look at the Using C++ Models with Qt Quick Views chapter of Qt's documentation. It should get you started.



  • @SGaist I'm a little confused. Perhaps I'm going in the wrong direction. All of the examples I've seen use roles with one value for example QString. I was thinking I can return an object and access it's properties via display.propertyname. Is this even possible?

    Thanks!


  • Lifetime Qt Champion

    If you take the QObjectList based example you'll see that you can access your object properties.



  • @SGaist First of all, thanks for all of your help. I still have a question though. Do you have to use the QObjectList to access your object properties or is this possible through QAbstractListModel?



  • @clarity Sure, you can also return QObjects from QAbstractListModel::data().


  • Qt Champions 2016

    @jpnurmi from docs I read that I can use a list of QObject* as model data, but this model doesn't know if list content changes I have to reset the model. haven't tested yet but doesn't sound flexible.
    In BlackBerry Cascades implementation I can fill a data model with a list of QObject* and use the properties of QObject* data classes in list view items. editing properties in QML the C++ QObject* was changed and changes automatically proposed to QML. very convenient: have a list, tap on row, push details page, change values, pop page and list values are automagically also changed.
    ...reading through the docs and examples to find out how to do this with Qt 5.6 ... landing in this thread.
    from your answer I have the hope that there's a way to deal with QObject* data from C++ in QML, but perhaps I misunderstood.



  • @ekkescorner QObjectList is indeed not great for dynamic lists, because there's no way to monitor for changes. Here's a dummy example of using QAbstractListModel + QObject:

    // main.cpp
    #include <QtGui>
    #include <QtQml>
    
    class ExampleModel : public QAbstractListModel
    {
        Q_OBJECT
    
    public:
        ExampleModel(QObject *parent = 0) : QAbstractListModel(parent)
        {
            for (int i = 0; i < 10; ++i) {
                QObject *object = new QObject(this);
                object->setObjectName(QString::number(i) + QString::number(i));
                m_objects.append(object);
            }
        }
    
        int rowCount(const QModelIndex &parent) const
        {
            if (parent.isValid())
                return 0;
    
            return m_objects.count();
        }
    
        QVariant data(const QModelIndex &index, int role) const
        {
            if (!index.isValid() || role != Qt::UserRole)
                return QVariant();
    
            return QVariant::fromValue(m_objects.at(index.row()));
        }
    
        QHash<int, QByteArray> roleNames() const
        {
            QHash<int, QByteArray> roles;
            roles.insert(Qt::UserRole, "example");
            return roles;
        }
    
    private:
        QObjectList m_objects;
    };
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        qmlRegisterType<ExampleModel>("example", 1, 0, "ExampleModel");
    
        QQmlApplicationEngine engine;
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
        return app.exec();
    }
    
    #include "main.moc"
    
    // main.qml
    import QtQuick 2.5
    import QtQuick.Window 2.2
    import example 1.0
    
    Window {
        visible: true
    
        ListView {
            spacing: 20
            anchors.fill: parent
            model: ExampleModel { }
            delegate: Text {
                text: example.objectName
            }
        }
    }
    

  • Qt Champions 2016

    @jpnurmi thanks. sounds great - will try it out soon.


  • Qt Champions 2016

    @jpnurmi cool :)
    did some first tests with QAbstractListModel filled with some Customer* (QObject)
    inserted customers, removed customers, changed properties via C++
    all correct refreshed in QML ListView

    seems I can "port" most of my data model logic / UI from BlackBerry Cascades to Qt 5.6 :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.