Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. 3-dimensional model
Forum Updated to NodeBB v4.3 + New Features

3-dimensional model

Scheduled Pinned Locked Moved Solved QML and Qt Quick
7 Posts 2 Posters 416 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Y Offline
    Y Offline
    Yrog
    wrote on last edited by
    #1

    Hi there,

    I have a set of data that I want to display as a list (in a non-qml sense).

    One line will contain the following :

    • a boolean -> Checkbox (not represented in the code below)
    • a text for description -> Text
    • a list of datetime (or list of string)-> Combobox

    In my mind, this looks like a 3-dimensional data: so I assume QAbstractItemModel would fit but can find a solution.

    I struggle with the data in the combobox. Here is my code:

    main.qml

    import QtQuick 2.15
    import QtQuick.Window 2.15
    import QtQuick.Controls 2.15
    
    Window {
        width: 640
        height: 480
        visible: true
        title: qsTr("3D Model")
    
        ListView{
            anchors.fill:parent
            model: mymodel
            clip:true
            delegate: Rectangle{
                width:parent.width;
                height:50;
                color: model["color"]
    
                Text{
                    id:txt
                    height: parent.height
                    anchors.left: parent.left
                    anchors.right: cbb.left
                    text: model["display"]
                    verticalAlignment: Text.AlignVCenter
                }
                ComboBox{
                    id:cbb
                    width: 200
                    height: parent.height
                    anchors.right: parent.right
                    model: model["runList"]
                    delegate: Text{
                        text: "display"
                    }
                }
            }
        }
    }
    

    testmodel.cpp

    #include "testmodel.h"
    
    #include <QDateTime>
    #include <QDebug>
    
    TestModel::TestModel()
    {
        qDebug() << Q_FUNC_INFO;
    
        QList<QString> dateTimeList;
        dateTimeList.append(QDateTime::currentDateTime().toString(Qt::ISODate));
    
        for (quint8 i=0; i < 20; i++){
            dateTimeList.append(QDateTime::currentDateTime().toString(Qt::ISODate));
            Test* test = new Test(QString("%1 - Test Number %1").arg(i), dateTimeList);
            m_testList.append(test);
        }
    }
    
    int TestModel::rowCount(const QModelIndex &parent) const
    {
    
        return m_testList.count();
    }
    
    QVariant TestModel::data(const QModelIndex &index, int role) const
    {
        switch (role){
        case Qt::DisplayRole: return m_testList.at(index.row())->name();
        case Qt::DecorationRole: return m_testList.at(index.row())->color();
        case Qt::UserRole+1: return m_testList.at(index.row())->runList();
        }
    
        return QVariant();
    }
    
    QHash<int, QByteArray> TestModel::roleNames() const
    {
        QHash<int, QByteArray> roles;
    
        roles[Qt::DisplayRole] = "display";
        roles[Qt::DecorationRole] = "color";
        roles[Qt::UserRole+1] = "runList";
    
        return roles;
    }
    

    testmodel.h

    #ifndef TestModel_H
    #define TestModel_H
    
    #include <QAbstractListModel>
    
    #include "test.h"
    
    class TestModel : public QAbstractListModel
    {
        Q_OBJECT
    public:
        TestModel();
    
    public:
        // QAbstractItemModel interface
        virtual int rowCount(const QModelIndex &parent) const override;
        virtual QVariant data(const QModelIndex &index, int role) const override;
        virtual QHash<int, QByteArray> roleNames() const override;
    
    private:
        QList<Test*> m_testList;
    
    
    };
    
    
    #endif // TestModel_H
    
    

    test.cpp

    #include "test.h"
    
    #include <QRandomGenerator>
    #include <QDebug>
    
    Test::Test(const QString &newName, const QStringList &newRunList):
        m_name(newName),
        m_runList(newRunList)
    {
        int red = QRandomGenerator::global()->bounded(0, 256);
        int green = QRandomGenerator::global()->bounded(0, 256);
        int blue = QRandomGenerator::global()->bounded(0, 256);
        m_color = QColor(red, green, blue);
    
        qDebug() << Q_FUNC_INFO << "Creating " << m_name << "with color: " << m_color;
    }
    
    const QString &Test::name() const
    {
        return m_name;
    }
    
    void Test::setName(const QString &newName)
    {
        m_name = newName;
    }
    
    const QStringList &Test::runList() const
    {
        return m_runList;
    }
    
    void Test::setRunList(const QStringList &newRunList)
    {
        m_runList = newRunList;
    }
    
    const QColor &Test::color() const
    {
        return m_color;
    }
    

    test.h

    #ifndef Test_H
    #define Test_H
    
    #include <QString>
    #include <QStringList>
    #include <QColor>
    
    class Test
    {
    public:
        Test(const QString &newName, const QStringList &newRunList);
        const QString &name() const;
        void setName(const QString &newName);
    
        const QStringList &runList() const;
        void setRunList(const QStringList &newRunList);
    
        const QColor &color() const;
    
    private:
        QString m_name;
        QStringList m_runList;
        QColor  m_color;
    };
    
    #endif // Test_H
    

    main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    #include <QDebug>
    
    #include "testmodel.h"
    
    int main(int argc, char *argv[])
    {
    #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    #endif
        QGuiApplication app(argc, argv);
    
        qmlRegisterType<TestModel> ("TModel", 1, 0, "TestModel");
        qDebug() << Q_FUNC_INFO;
        TestModel model ;
        qDebug() << Q_FUNC_INFO;
    
        QQmlApplicationEngine engine;
        engine.rootContext()->setContextProperty("mymodel", &model);
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        engine.load(url);
    
    
        return app.exec();
    }
    
    

    An advise would be appreciated.

    Yrog

    1 Reply Last reply
    0
    • fcarneyF Offline
      fcarneyF Offline
      fcarney
      wrote on last edited by
      #6

      I got your original code working:

      import QtQuick 2.15
      import QtQuick.Window 2.15
      import QtQuick.Controls 2.15
      
      Window {
          width: 640
          height: 480
          visible: true
          title: qsTr("3D Model")
      
          ListView{
              anchors.fill:parent
              model: mymodel
              clip:true
              delegate: Rectangle{
                  id: rect
      
                  property var sourcemodel: model
      
                  width: parent.width;
                  height: 50
                  color: sourcemodel.color
      
                  Text{
                      id:txt
                      height: parent.height
                      anchors.left: parent.left
                      anchors.right: cbb.left
                      text: display
                      verticalAlignment: Text.AlignVCenter
                  }
                  ComboBox{
                      id:cbb
                      width: 200
                      height: parent.height
                      anchors.right: parent.right
                      model: runList
                      delegate: Text{
                          text: modelData
                      }
                  }
              }
          }
      }
      

      Look carefully how I used the role names. For instance using "color" as a role name is not a good idea. runList and display are fine because those names don't typically collide. Also note where I used modelData for the ComboBox delegate. This is because it is a list of items rather than a full blown item model.

      C++ is a perfectly valid school of magic.

      1 Reply Last reply
      1
      • fcarneyF Offline
        fcarneyF Offline
        fcarney
        wrote on last edited by
        #2
        ComboBox{
                        id:cbb
                        width: 200
                        height: parent.height
                        anchors.right: parent.right                
                        model: model["runList"]
                        delegate: Text{
                            text: modelData // "display" is just a string
                        }
                    }
        

        modelData is where the data is placed when feeding it a list without. Otherwise the data follows the roleNames.

        Also:

        model: model.runList  // really only needed if there is ambiguous naming going on
        or
        model: runList // when using a proper model you should be able to use role name like this
        

        C++ is a perfectly valid school of magic.

        1 Reply Last reply
        0
        • Y Offline
          Y Offline
          Yrog
          wrote on last edited by
          #3

          Thanks for your reply. But...

          qrc:/main.qml:34: TypeError: Cannot read property 'runList' of undefined
          

          The role "runList" seems correct as I tried model["runList"] in Text{}, the trace in Test::runList() returns the list (but Text is unable to display a list :) )

          1 Reply Last reply
          0
          • fcarneyF Offline
            fcarneyF Offline
            fcarney
            wrote on last edited by
            #4
            delegate: Rectangle{
              id: rect
            ...
            ComboBox {
              model: rect.model.runList  // or just runList by itself since it is a role, using role is preferred
            

            The model in the combobox was confusing the model injected by the view.

            C++ is a perfectly valid school of magic.

            1 Reply Last reply
            0
            • Y Offline
              Y Offline
              Yrog
              wrote on last edited by
              #5

              Many thanks @fcarney for the time spent on my issue.

              I finally changed my mind and simplified the problem. I converted the model in model["runList"] in a basic QStringList which is enough for my needs right now. Not the most elegant way to solve my issue but it works.

              But I can't just get a working solution for the model in model, even with your suggestions. Quite frustrating.

              Thanks again

              1 Reply Last reply
              0
              • fcarneyF Offline
                fcarneyF Offline
                fcarney
                wrote on last edited by
                #6

                I got your original code working:

                import QtQuick 2.15
                import QtQuick.Window 2.15
                import QtQuick.Controls 2.15
                
                Window {
                    width: 640
                    height: 480
                    visible: true
                    title: qsTr("3D Model")
                
                    ListView{
                        anchors.fill:parent
                        model: mymodel
                        clip:true
                        delegate: Rectangle{
                            id: rect
                
                            property var sourcemodel: model
                
                            width: parent.width;
                            height: 50
                            color: sourcemodel.color
                
                            Text{
                                id:txt
                                height: parent.height
                                anchors.left: parent.left
                                anchors.right: cbb.left
                                text: display
                                verticalAlignment: Text.AlignVCenter
                            }
                            ComboBox{
                                id:cbb
                                width: 200
                                height: parent.height
                                anchors.right: parent.right
                                model: runList
                                delegate: Text{
                                    text: modelData
                                }
                            }
                        }
                    }
                }
                

                Look carefully how I used the role names. For instance using "color" as a role name is not a good idea. runList and display are fine because those names don't typically collide. Also note where I used modelData for the ComboBox delegate. This is because it is a list of items rather than a full blown item model.

                C++ is a perfectly valid school of magic.

                1 Reply Last reply
                1
                • Y Offline
                  Y Offline
                  Yrog
                  wrote on last edited by
                  #7

                  Thanks,

                  Your solution works !

                  But the two lines below were not a concern as color: model["color"] worked fine

                  property var sourcemodel: model
                  color: sourcemodel.color
                  

                  what solved my issue in your response is

                  model: runList
                  

                  My understanding was that model["runList"] and model: runList were equivalent, just needed for desambiguation. I had wrong but don't know why...

                  @fcarney thanks for your patience, that solved my issue !

                  1 Reply Last reply
                  0

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved