Preparing your Qt Quick gallery entry point
First of all, you need to link this project to our gallery-core library. We already covered how to link an internal library in Chapter 12, Conquering the Desktop UI. For more details, refer to it. This is the updated gallery-mobile.pro file:
TEMPLATE = app QT += qml quick sql svg CONFIG += c++11 SOURCES += main.cpp RESOURCES += gallery.qrc LIBS += -L$$OUT_PWD/../gallery-core/ -lgallery-core INCLUDEPATH += $$PWD/../gallery-core DEPENDPATH += $$PWD/../gallery-core contains(ANDROID_TARGET_ARCH,x86) { ANDROID_EXTRA_LIBS = $$[QT_INSTALL_LIBS]/libQt5Sql.so }
Please notice that we made several changes here:
- We added the sql module to deploy the dependency on your mobile device
- We added the svg module for the button icons
- The qml.qrc file has been renamed in gallery.qrc
- We linked the gallery-core library
- By default, the sql shared object (libQt5Sql.so) will not be deployed on your Android x86 device. You have to explicitly include it in your .pro file.
You can now use classes from the gallery-core library in our gallery-mobile application. Let's see how to bind C++ models with QML. This is the updated main.cpp:
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include <QQuickView> #include "AlbumModel.h" #include "PictureModel.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); AlbumModel albumModel; PictureModel pictureModel(albumModel); QQmlApplicationEngine engine; QQmlContext* context = engine.rootContext(); context->setContextProperty("albumModel", &albumModel); context->setContextProperty("pictureModel", &pictureModel); engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml"))); return app.exec(); }
Our models will be instantiated in C++ and exposed to QML using the root QQmlContext object. The setContextProperty() function allows us to bind a C++ QObject to a QML property. The first argument will be the QML property name. We are only binding a C++ object to a QML property; the context object does not take ownership of this object.
Let's now talk about the mobile application itself. We will define three pages with specific roles:
- AlbumListPage
- Displays existing albums
- Album creation
- Album selection
- AlbumPage
- Displays existing pictures as thumbnails
- Adds pictures in album
- Album rename
- Album deletion
- Picture selection
- PicturePage
- Displays selected picture
- Picture selection
- Picture deletion
To handle the navigation, we will use a StackView component from Qt Quick Controls. This QML component implements a stack-based navigation. You can push a page when you want to display it. When the user requests to go back, you can pop it. Here is the workflow using a StackView component for our gallery mobile application. The page with the solid border is the page currently displayed on screen:
This is the implementation of main.qml:
import QtQuick 2.6 import QtQuick.Controls 2.0 ApplicationWindow { readonly property alias pageStack: stackView id: app visible: true width: 768 height: 1280 StackView { id: stackView anchors.fill: parent initialItem: AlbumListPage {} } onClosing: { if (Qt.platform.os == "android") { if (stackView.depth > 1) { close.accepted = false stackView.pop() } } } }
This main file is really simple. The application is constructed around the StackView component. We set the id property to allow our StackView to be identified and referred to by other QML objects. The anchors property will set stackView to fill its parent, the ApplicationWindow type. Finally, we set the initialItem property to a page, AlbumListPage that will be implemented soon.
On Android, onClosing will be executed each time the user presses the back button. To mimic a native Android application, we will first pop the last stacked page before really closing the application.
At the top of the file, we define a property alias for the stackView. A property alias is a simple reference to another existing property. This alias will be useful to access stackView from other QML components. To prevent a QML component to crush the stackView we are using the readonly keyword. After initialization, the components can access the property but not change its value.