Displaying albums with ListView
Let's make our first page for this mobile application! Create a file in gallery.qrc called AlbumListPage.qml. Here is the page header implementation:
import QtQuick 2.0 import QtQuick.Layouts 1.3 import QtQuick.Controls 2.0 Page { header: ToolBar { Label { Layout.fillWidth: true text: "Albums" font.pointSize: 30 } } ... }
A Page is a container control with a header and footer. In this application, we will only use the header item. We assign a ToolBar to the header property. The height of this toolbar will be handled by Qt and will be adjusted depending on the target platform. In this first simple implementation, we only put a Label displaying the text "Albums".
Add a ListView element to this page after the header initialization:
ListView { id: albumList model: albumModel spacing: 5 anchors.fill: parent delegate: Rectangle { width: parent.width height: 120 color: "#d0d1d2" Text { text: name font.pointSize: 16 color: "#000000" anchors.verticalCenter: parent.verticalCenter } } }
The Qt Quick ListView is the Qt Widget QListView equivalent. It displays a list of items from a provided model. We set the model property to value albumModel. This refers to the C++ model from main.cpp file accessible from QML because we used the setContextProperty() function. In Qt Quick, you must provide a delegate to describe how a row will be displayed. In this case, a row will only display the album's name with a Text item. Accessing the album's name in QML is easy because our AlbumModel model exposes its role list to QML. Let's refresh your memory concerning the overridden roleNames() function of AlbumModel:
QHash<int, QByteArray> AlbumModel::roleNames() const { QHash<int, QByteArray> roles; roles[Roles::IdRole] = "id"; roles[Roles::NameRole] = "name"; return roles; }
So each time your delegate from Qt Quick uses the name role, it will call the AlbumModel function data() with the correct role integer and return the correct album name string.
To handle the mouse, click on a row and add a MouseArea element on the delegate:
ListView { ... delegate: Rectangle { ... MouseArea { anchors.fill: parent onClicked: { albumList.currentIndex = index pictureModel.setAlbumId(id) pageStack.push("qrc:/qml/AlbumPage.qml", { albumName: name, albumRowIndex: index }) } } } }
The MouseArea is an invisible item that can be used with any visible item to handle mouse events. This also applies to a simple touch on a phone touch screen. Here we tell the MouseArea element to take the full area of the parent Rectangle.
In our case, we only perform tasks on the clicked signal. We update the currentIndex of the ListView with index. This index is a special role containing the index of the item in the model.
When the user clicks, we will tell pictureModel to load the selected album with the pictureModel.setAlbumId(id) call. We will see soon how QML can call C++ methods.
Finally, we push AlbumPage on pageStack property. The push() function allows us to set a list of QML properties using a {key: value, ... } syntax. Each property will be copied into the pushed item. Here the name and the index will be copied in the albumName and albumRowIndex properties of AlbumPage. It is a simple yet powerful way to instantiate a QML page with properties arguments.
From your QML code, you can only call some specific C++ methods:
- Properties (using Q_PROPERTY)
- Public slot
- Function decorated as invokable (using Q_INVOKABLE)
In this case we will decorate PictureModel::setAlbumId() as Q_INVOKABLE, please update the PictureModel.h file:
class GALLERYCORESHARED_EXPORT PictureModel : public QAbstractListModel { Q_OBJECT public: ... Q_INVOKABLE void setAlbumId(int albumId); ... };