Theming the application with a QML singleton

Styling and theming a QML application can be done in various ways. In this chapter, we will declare a QML singleton with the theme data used by custom components. Moreover, we will also create a custom Page component to handle the toolbar and its default item (back button and page's title).

Please create a new Style.qml file:

pragma Singleton 
import QtQuick 2.0 
 
QtObject { 
    property color text: "#000000" 
 
    property color windowBackground: "#eff0f1" 
    property color toolbarBackground: "#eff0f1" 
    property color pageBackground: "#fcfcfc" 
    property color buttonBackground: "#d0d1d2" 
 
    property color itemHighlight: "#3daee9" 
} 

We declare a QtObject component that will only contain our theme properties. A QtObject is a non-visual QML component.

Declaring a singleton type in QML requires two steps. First you need to use the pragma singleton, it will indicate the use of a single instance of the component. The second step is to register it. This can be done in C++ or by creating a qmldir file. Let's see the second step. Create a new plain-text file called qmldir:

singleton Style 1.0 Style.qml 

This simple line will declare a QML singleton type named Style with the version 1.0 from the file named Style.qml.

It is now time to use these theme properties in custom components. Let's see a simple example. Create a new QML file called ToolBarTheme.qml:

import QtQuick 2.0 
import QtQuick.Controls 2.0 
 
import "." 
 
ToolBar { 
     background: Rectangle { 
         color: Style.toolbarBackground 
     } 
 
} 

This QML object describes a customized ToolBar. Here, the background element is a simple Rectangle with our color. We can easily access our singleton Style and its theme property using Style.toolbarBackground.

QML Singletons require an explicit import to load the qmldir file. The  import "." is a workaround for this Qt bug. For more information, please check  https://bugreports.qt.io/browse/QTBUG-34418.

We will now create a QML file PageTheme.qml, with the aim of containing all the code related to the page's toolbar and theme:

import QtQuick 2.0 
 
import QtQuick.Layouts 1.3 
import Qt.labs.controls 1.0 
import QtQuick.Controls 2.0 
import "." 
 
Page { 
 
    property alias toolbarButtons: buttonsLoader.sourceComponent 
    property alias toolbarTitle: titleLabel.text 
 
    header: ToolBarTheme { 
        RowLayout { 
            anchors.fill: parent 
            ToolButton { 
                background: Image { 
                    source: "qrc:/res/icons/back.svg" 
                } 
                onClicked: { 
                    if (stackView.depth > 1) { 
                        stackView.pop() 
                    } 
                } 
            } 
 
            Label { 
                id: titleLabel 
                Layout.fillWidth: true 
                color: Style.text 
                elide: Text.ElideRight 
                font.pointSize: 30 
            } 
 
            Loader { 
                Layout.alignment: Qt.AlignRight 
                id: buttonsLoader 
            } 
        } 
    } 
 
    Rectangle { 
        color: Style.pageBackground 
        anchors.fill: parent 
    } 
} 

This PageTheme element will customize the page's header. We use our previously created ToolBarTheme. This toolbar only contains a RowLayout element to display items horizontally in one row. This layout contains three elements:

  • ToolButton: This is the "back" that displays an image from gallery.qrc and pops the current page if required
  • Label: This is the element that displays the page title
  • Loader: This is the element that allows a page to dynamically add specific items in this generic toolbar

The Loader element owns a sourceComponent property. In this application, this property can be assigned by PageTheme pages to add specific buttons. These buttons will be instantiated at runtime.

The PageTheme pages also contain a Rectangle element that fits the parent and configures the page background color using the Style.pageBackground.

Now that our Style.qml and PageTheme.qml files are ready, we can update the AlbumListPage.qml file to use it:

import QtQuick 2.6 
import QtQuick.Controls 2.0 
import "." 
 
PageTheme { 
 
    toolbarTitle: "Albums" 
 
    ListView { 
        id: albumList 
        model: albumModel 
        spacing: 5 
        anchors.fill: parent 
 
        delegate: Rectangle { 
            width: parent.width 
            height: 120 
            color: Style.buttonBackground 
 
            Text { 
                text: name 
                font.pointSize: 16 
                color: Style.text 
                anchors.verticalCenter: parent.verticalCenter 
            } 
            ... 
        } 
    } 
} 

Now that AlbumListPage is a PageTheme element, we do not manipulate header directly. We only need to set the property toolbarTitle to display a nice "Albums" text in the toolbar. We can also enjoy nice colors using properties from the Style singleton.

By centralizing the theme properties in a single file, you can easily change the look and feel of your application. The source code of the project also contains a dark theme.