Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    [SOLVED]Page wise scrolling in GridView

    QML and Qt Quick
    1
    3
    3170
    Loading More Posts
    • 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.
    • S
      swegmann last edited by

      How can I make sure that scrolling snaps to certain page-borders when using a GridView?
      Let's say I have a 4x3 grid of items in a grid view. When I now swipe to the left I want the view to snap to the next 4x3 grid and not just move one item to the left.
      Currently I implemented this by nesting GridLayout items inside a ListView which has snap set to SnapOneItem. However this way it gets quite complicated to create a usable model in C++. I want the items inside this list to be taken from a contiguous list. But with the nesting I'd probably have to find a way of splitting the model into a model for each Grid inside the list. It sounds complex and I want to avoid that.

      A similar question was asked here for Symbian quite some time ago: http://qt-project.org/forums/viewthread/10743 Unfortunately no answer about the paging part yet.

      1 Reply Last reply Reply Quote 0
      • S
        swegmann last edited by

        With the help of a colleague I finally found a workable solution for this.

        The basis is a QAbstractListModel that provides all the items that should be shown in the pages. I added three int Q_PROPERTYs called 'pages', 'columns' and 'rows' that are set by loading corresponding config files and by calculating the amount of 'pages' by dividing the total amount of items by the amount of items per page. This list is published towards QML using the setContextProperty() function.

        @
        //...
        MySimpleList ui_mysimple_list;
        engine.rootContext()->setContextProperty("ui_mysimple_list", &ui_mysimple_list);
        //...
        @

        To split this list into several pages I created a page model using an QAbstractProxyModel.

        @
        class MyPageModel : public QAbstractProxyModel
        {
        Q_OBJECT

        Q_PROPERTY(int pageNumber READ pageNumber WRITE setPageNumber NOTIFY pageNumberChanged)
        Q_PROPERTY(int pageSize READ pageSize WRITE setPageSize NOTIFY pageSizeChanged)
        Q_PROPERTY(QObject* mainModel READ mainModel WRITE setMainModel)
        

        signals:
        void pageNumberChanged(int newPageNumber);
        void pageSizeChanged(int newPageSize);

        public:
        explicit MyPageModel(QObject *parent = 0);

        virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const
        {
            if (!sourceModel())
                return QModelIndex();
        
            int proxyRow = sourceIndex.row() % _pageSize;
            return index(proxyRow, sourceIndex.column(), QModelIndex());
        }
        
        virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const
        {
            if (!sourceModel())
                return QModelIndex();
        
            int sourceRow = proxyIndex.row() + _pageNumber * _pageSize;
            return index(sourceRow, proxyIndex.column(), QModelIndex());
        }
        
        virtual int columnCount(const QModelIndex &parent) const;
        virtual int rowCount(const QModelIndex &parent) const
        {
            Q_UNUSED(parent);
            if (_pageNumber<0)
                return 0;
        
            if (!sourceModel())
                return 0;
        
            int sourceCount = sourceModel()->rowCount();
            int remainderSize = sourceCount - (_pageSize*_pageNumber);
            if (remainderSize<_pageSize)
                return remainderSize;
            return _pageSize;
        }
        
        virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
        {
            Q_UNUSED(parent);
            return createIndex(row, column);
        }
        
        virtual QModelIndex parent(const QModelIndex &child) const;
        
        virtual QHash<int, QByteArray> roleNames() const
        {
            if (!sourceModel())
                return QHash<int, QByteArray>();
        
            return sourceModel()->roleNames();
        }
        
        QObject *mainModel() const;
        int pageNumber() const;
        int pageSize() const;
        

        public slots:
        void setMainModel(QObject *mainModel);
        void setPageNumber(int newPageNumber);
        void setPageSize(int newPageSize);

        private:
        int _pageNumber;
        int _pageSize;
        };
        @

        This class is published towards QML as a constructable type:

        @
        qmlRegisterType<MyPageModel>("PackagePath", 1, 0, "MyPageModel");
        @

        This combination can now easily be used in QML as follows:

        @
        Rectangle {
        Item {
        anchors.fill: parent

            ListView {
                id: selection_list
        
                anchors.fill: parent
        
                interactive: ui_mysimple_list.pages > 1 // prevent scrolling when only one page is available
        
                orientation: Qt.Horizontal
        
                clip: true
                snapMode: ListView.SnapOneItem
        
                model: ui_mysimple_list.pages  // we only need the amount of pages to generate enough list items at this level
                delegate: selection_list_page
            }
        }
        
        Component {
            id: selection_list_page
        
            GridView {
                interactive: false  // no scrolling inside the GridView
        
                model: MyPageModel {
                    mainModel: ui_mysimple_list
                    pageNumber: index
                    pageSize: ui_mysimple_list.columns * ui_mysimple_list.rows
                }
        
                delegate: grid_delegate
            }
        }
        
        Component {
            id: grid_delegate
        
            // here comes your code to display one single list item
        
        }
        

        }
        @

        1 Reply Last reply Reply Quote 0
        • S
          swegmann last edited by

          With the help of a colleague I finally found a workable solution for this.

          The basis is a QAbstractListModel that provides all the items that should be shown in the pages. I added three int Q_PROPERTYs called 'pages', 'columns' and 'rows' that are set by loading corresponding config files and by calculating the amount of 'pages' by dividing the total amount of items by the amount of items per page. This list is published towards QML using the setContextProperty() function.

          @
          //...
          MySimpleList ui_mysimple_list;
          engine.rootContext()->setContextProperty("ui_mysimple_list", &ui_mysimple_list);
          //...
          @

          To split this list into several pages I created a page model using an QAbstractProxyModel.

          @
          class MyPageModel : public QAbstractProxyModel
          {
          Q_OBJECT

          Q_PROPERTY(int pageNumber READ pageNumber WRITE setPageNumber NOTIFY pageNumberChanged)
          Q_PROPERTY(int pageSize READ pageSize WRITE setPageSize NOTIFY pageSizeChanged)
          Q_PROPERTY(QObject* mainModel READ mainModel WRITE setMainModel)
          

          signals:
          void pageNumberChanged(int newPageNumber);
          void pageSizeChanged(int newPageSize);

          public:
          explicit MyPageModel(QObject *parent = 0);

          virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const
          {
              if (!sourceModel())
                  return QModelIndex();
          
              int proxyRow = sourceIndex.row() % _pageSize;
              return index(proxyRow, sourceIndex.column(), QModelIndex());
          }
          
          virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const
          {
              if (!sourceModel())
                  return QModelIndex();
          
              int sourceRow = proxyIndex.row() + _pageNumber * _pageSize;
              return index(sourceRow, proxyIndex.column(), QModelIndex());
          }
          
          virtual int columnCount(const QModelIndex &parent) const;
          virtual int rowCount(const QModelIndex &parent) const
          {
              Q_UNUSED(parent);
              if (_pageNumber<0)
                  return 0;
          
              if (!sourceModel())
                  return 0;
          
              int sourceCount = sourceModel()->rowCount();
              int remainderSize = sourceCount - (_pageSize*_pageNumber);
              if (remainderSize<_pageSize)
                  return remainderSize;
              return _pageSize;
          }
          
          virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
          {
              Q_UNUSED(parent);
              return createIndex(row, column);
          }
          
          virtual QModelIndex parent(const QModelIndex &child) const;
          
          virtual QHash<int, QByteArray> roleNames() const
          {
              if (!sourceModel())
                  return QHash<int, QByteArray>();
          
              return sourceModel()->roleNames();
          }
          
          QObject *mainModel() const;
          int pageNumber() const;
          int pageSize() const;
          

          public slots:
          void setMainModel(QObject *mainModel);
          void setPageNumber(int newPageNumber);
          void setPageSize(int newPageSize);

          private:
          int _pageNumber;
          int _pageSize;
          };
          @

          This class is published towards QML as a constructable type:

          @
          qmlRegisterType<MyPageModel>("PackagePath", 1, 0, "MyPageModel");
          @

          This combination can now easily be used in QML as follows:

          @
          Rectangle {
          Item {
          anchors.fill: parent

              ListView {
                  id: selection_list
          
                  anchors.fill: parent
          
                  interactive: ui_mysimple_list.pages > 1 // prevent scrolling when only one page is available
          
                  orientation: Qt.Horizontal
          
                  clip: true
                  snapMode: ListView.SnapOneItem
          
                  model: ui_mysimple_list.pages  // we only need the amount of pages to generate enough list items at this level
                  delegate: selection_list_page
              }
          }
          
          Component {
              id: selection_list_page
          
              GridView {
                  interactive: false  // no scrolling inside the GridView
          
                  model: MyPageModel {
                      mainModel: ui_mysimple_list
                      pageNumber: index
                      pageSize: ui_mysimple_list.columns * ui_mysimple_list.rows
                  }
          
                  delegate: grid_delegate
              }
          }
          
          Component {
              id: grid_delegate
          
              // here comes your code to display one single list item
          
          }
          

          }
          @

          1 Reply Last reply Reply Quote 0
          • First post
            Last post