QML SectionScroller vs. QAbstractListModel

A SectionScroller essentially allows quick scrolling in large lists. Though, there are some pitfalls when you want to use a custom C++/Qt based model with a SectionScroller in QML. Please note that this should work with a QAbstractItemModel based model class as well as with a model class derived from QAbstractList model. Though, I didn’t test an implementation based on QAbstractItemModel yet.

Here is an example of a QML SectionScroller in action:

The working principle of a SectionScroller is pretty simple. You simply create a ListModel, a ListView, and a SectionScroller and QML takes care of the whole magic. See the following listing for a simple example (This is an excerpt of the source code that had been used for the above screenshot.):

  ListModel{
    id: myModel
    ListElement{ name: "foo"; category: "abc" }
    ListElement{ name: "bar"; category: "abc" }
    ...
    ListElement{ name: "12"; category: "xyz" }
    ...
    ListElement{ name: "12"; category: "xyz" }
    ListElement{ name: "34"; category: "def" }
    ...
    ListElement{ name: "78"; category: "def" }
  }

  ListView {
    id: myListView
    anchors.fill: parent
    model: myModel

    delegate: Text{
      text: name
      font.pointSize: 30
    }

    section {
      property: "category"
      criteria: ViewSection.FullString
      delegate: Rectangle {
        color: "lightblue"
        width: parent.width
        height: childrenRect.height + 4
        Text {
          anchors.horizontalCenter: parent.horizontalCenter
          font.pointSize: 24
          text: section
        }
      }
    }
  }

  SectionScroller {
    listView: myListView
  }

The above example uses a QML ListModel. When using a custom C++/Qt based model things are getting a little bit more complicated.

In this example the following data model is used. A simple C++/Qt class is used as entity. In the following listing only the parts relevant for this example are shown:

class Entry : public QObject
{
  Q_OBJECT
  Q_PROPERTY(QString category READ category WRITE setCategory NOTIFY categoryChanged)
  Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)

public:
  ...
  QString category() const { return m_category; }
  QString name() const { return m_name; }

  void setCategory(QString category){
    m_category = category;
    emit categoryChanged(category);
  }
  void setName(QString name){
    m_name = name;
    emit nameChanged(name);
  }

signals:
  void categoryChanged(QString);
  void nameChanged(QString);

private:
  QString m_category;
  QString m_name;
}

This model class has two properties “name” and “category”. In the corresponding model these properties are accessible via the “name” and “category” roles.

class EntryListModel : public QAbstractListModel
{
  Q_OBJECT
  // Needed to make SectionScroller happy.
  Q_PROPERTY(int count READ rowCount)

public:
  enum EntryRoles {
    NameRole = Qt::UserRole + 1,
    CategoryRole = Qt::UserRole + 2,
    ...
  }

  ...
  // Needed to make SectionScroller happy.
  Q_INVOKABLE Entry* get(int index) { return new Entry(m_entries.at(index); }
  ...
  Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const;

private:
  QList<Entry> m_entries;
  ...
}

This listing already shows two important points when using a SelectionScroller with a custom model. First, the model must provide a “count” property which indicates the number of elements in the model. This can be achieved easily by using the Q_PROPERTY macro and using the “rowCount” method as accessor for the “count” property. The “rowCount” method must be implemented for a QAbstractItemModel anyways. Second, the QML (more specific the accompanying JavaScript) code expects a “get(index)” method which returns the element in the model at the given index.

Last but not least the QML/JavaScript code in the SectionScroller “backend” expects the property used as section (here “category”) to be named equal in the model item class (Entry) and the model class role.

EntryListModel::EntryListModel(QObject *parent) :
  QAbstractListModel(parent)
{
  QHash roles;
  roles[NameRole] = "name";
  /*
   * Needed to make SectionScroller happy.
   * Take care to give the property used for naming the
   * section in the ListView the same name as in the
   * model element class (here Entry, see entry.h).
   */
  roles[CategoryRole] = "category";
  ...
  setRoleNames(roles);
}
About these ads
This entry was posted in Qt/QML, Snippets and tagged , , , , . Bookmark the permalink.

One Response to QML SectionScroller vs. QAbstractListModel

  1. Pingback: SectionScroller vs. QAbstractProxyModel « ruedigergad

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s