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. Assign data model elements to different pages of a SwipeView
Forum Updated to NodeBB v4.3 + New Features

Assign data model elements to different pages of a SwipeView

Scheduled Pinned Locked Moved Solved QML and Qt Quick
3 Posts 2 Posters 110 Views 1 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.
  • R Offline
    R Offline
    R_Johannes
    wrote on last edited by
    #1

    Hello,
    I have struggles to find a clean solution for my problem:
    There is a datamodel (QAbstractListModel) that holds data of different categories.
    Not I want to have a SwipeView to display all data that belongs to one category on a page 1 and the data for the next category on page 2 and so on.

    I created a simple application which showcases how it should be. But it comes with some flaws:

    • The complete data of the model is fetched for each page of the SwipeView because on each page there is the full ListView and the irrelevant items are just hidden
    • It seems a bit hacky to set the visibility and the height of the items based on the page index

    Is there a better way to achieve this kind of use case?
    I thought of using a TableModel instead of a ListModel in the backend and to display each column on a dedicated page of the SwipeView but could not get this running.

    Main.qml

    import QtQuick 2.15
    import QtQuick.Controls 2.15
    import ColorListModel
    
    Window {
        width: 200
        height: 200
        visible: true
    
        ColorListModel
        {
            id: colorListModel
        }
    
        SwipeView {
            id: swipe
            anchors.fill: parent
            focus: true
            Repeater {
                model: 4
    
                delegate: Item {
                    id: delegateItem
                    property int pageIndex: index
                    Column
                    {
                        spacing: 5
                        ListView {
                            id: lv
                            model: colorListModel
                            height: 150
                            width: 200
                            highlightFollowsCurrentItem: false
                            delegate: Rectangle {
                                visible: pageIndex === model.page
                                height: visible ? 50 : 0  // hacky solution to glue the list to the top
                                width: parent.width
                                color: model.color
                                border {color: "grey"; width: 3}
                                Text {
                                    anchors.centerIn: parent
                                    text: "page: " + model.page + " index: " + index
                                    font.pixelSize: 20
                                }
                            }
                        }
                        Text {
                            id: bottomLabel
                            anchors.horizontalCenter: parent.horizontalCenter
                            text: "page: " + delegateItem.pageIndex
                            font.pixelSize: 15
                        }
                    }
    
                }
            }
        }
    
        PageIndicator {
            count: swipe.count
            currentIndex: swipe.currentIndex
    
            anchors.bottom: swipe.bottom
            anchors.horizontalCenter: parent.horizontalCenter
        }
    }
    
    

    colorlistmodel.h

    #ifndef COLORLISTMODEL_H
    #define COLORLISTMODEL_H
    
    #include <QAbstractListModel>
    #include <QString>
    #include <QList>
    
    class ColorListModel : public QAbstractListModel
    {
        Q_OBJECT
    
    public:
        static constexpr const int DATA_PER_PAGE = 3;
        ColorListModel(QObject *parent = nullptr);
    
        int rowCount(const QModelIndex &parent = QModelIndex()) const override;
        QVariant data(const QModelIndex &index, int role) const override;
        QHash<int, QByteArray> roleNames() const override;
    
        enum Roles {
            PageRole = Qt::UserRole,
            ColorRole,
        };
    
        struct DataElement
        {
            int page;
            QString color;
        };
    
        int column() const;
        void setColumn(int newColumn);
    
    signals:
        void columnChanged();
    
    private:
        QList<DataElement> m_data;
    };
    
    #endif // COLORLISTMODEL_H
    
    

    colorlistmodel.cpp

    #include "colorlistmodel.h"
    #include <QString>
    #include <QList>
    
    ColorListModel::ColorListModel(QObject *parent)
        : QAbstractListModel(parent),
        m_data{{0, "red"}, {0, "green"}, {0, "blue"}, {1, "purple"}, {1, "lightgreen"}, {2, "brown"}, {2, "yellow"}, {2, "steelblue"}, {3, "orange"}, {3, "darkblue"}, {3, "darkgreen"}}
    {
    }
    
    int ColorListModel::rowCount(const QModelIndex &parent) const
    {
        Q_UNUSED(parent);
        return m_data.size();
    }
    
    QVariant ColorListModel::data(const QModelIndex &index, int role) const
    {
        //qInfo() << "data called for" << index.row();
    
        switch (role)
        {
        case PageRole:
            return m_data[index.row()].page;
            break;
        case ColorRole:
            return m_data[index.row()].color;
            break;
        default:
            return QVariant();
            break;
        }
    
        return QVariant();
    }
    
    
    QHash<int, QByteArray> ColorListModel::roleNames() const
    {
        static const QHash<int, QByteArray> mapping {
            {ColorRole, "color"},
            {PageRole, "page"},
        };
        return mapping;
    }
    
    

    main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include "colorlistmodel.h"
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
        qmlRegisterType<ColorListModel>("ColorListModel", 1, 0, "ColorListModel");
        QQmlApplicationEngine engine;
        QObject::connect(
            &engine,
            &QQmlApplicationEngine::objectCreationFailed,
            &app,
            []() { QCoreApplication::exit(-1); },
            Qt::QueuedConnection);
        engine.loadFromModule("ListModelExperimental", "Main");
    
        return app.exec();
    }
    
    jeremy_kJ 1 Reply Last reply
    0
    • R R_Johannes

      Hello,
      I have struggles to find a clean solution for my problem:
      There is a datamodel (QAbstractListModel) that holds data of different categories.
      Not I want to have a SwipeView to display all data that belongs to one category on a page 1 and the data for the next category on page 2 and so on.

      I created a simple application which showcases how it should be. But it comes with some flaws:

      • The complete data of the model is fetched for each page of the SwipeView because on each page there is the full ListView and the irrelevant items are just hidden
      • It seems a bit hacky to set the visibility and the height of the items based on the page index

      Is there a better way to achieve this kind of use case?
      I thought of using a TableModel instead of a ListModel in the backend and to display each column on a dedicated page of the SwipeView but could not get this running.

      Main.qml

      import QtQuick 2.15
      import QtQuick.Controls 2.15
      import ColorListModel
      
      Window {
          width: 200
          height: 200
          visible: true
      
          ColorListModel
          {
              id: colorListModel
          }
      
          SwipeView {
              id: swipe
              anchors.fill: parent
              focus: true
              Repeater {
                  model: 4
      
                  delegate: Item {
                      id: delegateItem
                      property int pageIndex: index
                      Column
                      {
                          spacing: 5
                          ListView {
                              id: lv
                              model: colorListModel
                              height: 150
                              width: 200
                              highlightFollowsCurrentItem: false
                              delegate: Rectangle {
                                  visible: pageIndex === model.page
                                  height: visible ? 50 : 0  // hacky solution to glue the list to the top
                                  width: parent.width
                                  color: model.color
                                  border {color: "grey"; width: 3}
                                  Text {
                                      anchors.centerIn: parent
                                      text: "page: " + model.page + " index: " + index
                                      font.pixelSize: 20
                                  }
                              }
                          }
                          Text {
                              id: bottomLabel
                              anchors.horizontalCenter: parent.horizontalCenter
                              text: "page: " + delegateItem.pageIndex
                              font.pixelSize: 15
                          }
                      }
      
                  }
              }
          }
      
          PageIndicator {
              count: swipe.count
              currentIndex: swipe.currentIndex
      
              anchors.bottom: swipe.bottom
              anchors.horizontalCenter: parent.horizontalCenter
          }
      }
      
      

      colorlistmodel.h

      #ifndef COLORLISTMODEL_H
      #define COLORLISTMODEL_H
      
      #include <QAbstractListModel>
      #include <QString>
      #include <QList>
      
      class ColorListModel : public QAbstractListModel
      {
          Q_OBJECT
      
      public:
          static constexpr const int DATA_PER_PAGE = 3;
          ColorListModel(QObject *parent = nullptr);
      
          int rowCount(const QModelIndex &parent = QModelIndex()) const override;
          QVariant data(const QModelIndex &index, int role) const override;
          QHash<int, QByteArray> roleNames() const override;
      
          enum Roles {
              PageRole = Qt::UserRole,
              ColorRole,
          };
      
          struct DataElement
          {
              int page;
              QString color;
          };
      
          int column() const;
          void setColumn(int newColumn);
      
      signals:
          void columnChanged();
      
      private:
          QList<DataElement> m_data;
      };
      
      #endif // COLORLISTMODEL_H
      
      

      colorlistmodel.cpp

      #include "colorlistmodel.h"
      #include <QString>
      #include <QList>
      
      ColorListModel::ColorListModel(QObject *parent)
          : QAbstractListModel(parent),
          m_data{{0, "red"}, {0, "green"}, {0, "blue"}, {1, "purple"}, {1, "lightgreen"}, {2, "brown"}, {2, "yellow"}, {2, "steelblue"}, {3, "orange"}, {3, "darkblue"}, {3, "darkgreen"}}
      {
      }
      
      int ColorListModel::rowCount(const QModelIndex &parent) const
      {
          Q_UNUSED(parent);
          return m_data.size();
      }
      
      QVariant ColorListModel::data(const QModelIndex &index, int role) const
      {
          //qInfo() << "data called for" << index.row();
      
          switch (role)
          {
          case PageRole:
              return m_data[index.row()].page;
              break;
          case ColorRole:
              return m_data[index.row()].color;
              break;
          default:
              return QVariant();
              break;
          }
      
          return QVariant();
      }
      
      
      QHash<int, QByteArray> ColorListModel::roleNames() const
      {
          static const QHash<int, QByteArray> mapping {
              {ColorRole, "color"},
              {PageRole, "page"},
          };
          return mapping;
      }
      
      

      main.cpp

      #include <QGuiApplication>
      #include <QQmlApplicationEngine>
      #include "colorlistmodel.h"
      
      int main(int argc, char *argv[])
      {
          QGuiApplication app(argc, argv);
          qmlRegisterType<ColorListModel>("ColorListModel", 1, 0, "ColorListModel");
          QQmlApplicationEngine engine;
          QObject::connect(
              &engine,
              &QQmlApplicationEngine::objectCreationFailed,
              &app,
              []() { QCoreApplication::exit(-1); },
              Qt::QueuedConnection);
          engine.loadFromModule("ListModelExperimental", "Main");
      
          return app.exec();
      }
      
      jeremy_kJ Offline
      jeremy_kJ Offline
      jeremy_k
      wrote on last edited by
      #2

      @R_Johannes said in Assign data model elements to different pages of a SwipeView:

      Hello,
      I have struggles to find a clean solution for my problem:
      There is a datamodel (QAbstractListModel) that holds data of different categories.
      Not I want to have a SwipeView to display all data that belongs to one category on a page 1 and the data for the next category on page 2 and so on.

      I created a simple application which showcases how it should be. But it comes with some flaws:

      • The complete data of the model is fetched for each page of the SwipeView because on each page there is the full ListView and the irrelevant items are just hidden
      • It seems a bit hacky to set the visibility and the height of the items based on the page index

      Is there a better way to achieve this kind of use case?

      Create a proxy model for each view. I didn't read the the code (TLDR; There's no need to have multiple C++ files and header files for such an example), but if you have something to differentiate in QML, presumably the same test could be performed in C++.

      Asking a question about code? http://eel.is/iso-c++/testcase/

      1 Reply Last reply
      1
      • R Offline
        R Offline
        R_Johannes
        wrote on last edited by R_Johannes
        #3

        Thanks for your reply and the hint with the proxy model.
        A good working solution was now implemented using the following design:

        • One AbstractListModel holding all the data
        • A SortFilterProxyModel to filter the data based on the page number is instanciated for each page, using the Repeater + Loader inside of the SwipeModel
        • The source component of the Loader holds a ListView that is using the ProxyModel as a model
        1 Reply Last reply
        1
        • R R_Johannes has marked this topic as solved on

        • Login

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