Using Material Design Icons in Qt Quick

When the Qt Project released Qt Quick Controls 2 with a new theme inspired by Google's Material Design guidelines, I felt like the look wouldn't be complete without the matching icon set. Here's how I got the icon theme to work with Qt.

Update: 5/30/2021: I've pushed a new version of this to GitHub, which includes definitions for all the icons available at the time of the update. I've also bundled the corresponding font file as well, for convenience. The JavaScript portion is now MIT licensed, with the font file being distributed under the SIL Open Font License, to match the Material Design Icons project.

Since I didn't want to import each icon as an individual image resource, I turned to the Material Design Icons font. While the project caters primarily to Web apps, it provides a single font file (distributed in a handful of formats) that contains all the Material Design icons that Google has released, along with a number of community-made icons that complement the theme.

Add the font file as a resource in our Qt project's QRC file, and register the font in the application's font database. If we started with the basic QML application template from Qt Creator, we could do this in the main.cpp file, as illustrated below:

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QFontDatabase>

int main(int argc, char *argv[]) {
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);
    QFontDatabase::addApplicationFont(":/materialdesignicons-webfont.ttf");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));

    return app.exec();
}

To actually use the icons in our application, we have to consider two implications of the choice to import them as a single font file, rather than as image resources. First, we can only access the icons from QML items that display text, such as the Text or Label element, or the Button control. This complicates the situation if we need a button control that shows both icon(s), and text, for example, though we could define a custom QML control to address this.

The other, more pressing concern is the fact that we have to know the specific Unicode character that corresponds to any icon that we want to display. The Material Design Icons project provides a CSS file that maps each icon to its own CSS class. To get a similar interface for our QML apps, I created a JavaScript object that matches the CSS class names with their corresponding Unicode characters.

To use the JavaScript object, we have to add the Icon.js file to the project, and import it into any QML file that needs access to icon names. I usually import the file as MdiFont, so I can get to the icons from MdiFont.Icon.<iconName>. To demonstrate, I've included the QML source that creates the sample app pictured at the top of this post:

main.qml

import QtQuick 2.7
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import "Icon.js" as MdiFont

ApplicationWindow {
    visible: true
    width: 720
    height: 480
    title: qsTr("Material Design Icons in QML")

    Rectangle {
        id: header
        color: "#3f51b5"
        height: 72
        anchors.top: parent.top
        anchors.left: parent.left
        anchors.right: parent.right

        Text {
            font.family: "Roboto"
            font.pointSize: 24
            text: qsTr("Material Design Icons in QML")
            color: "#ffffff"
            anchors.left: parent.left
            anchors.leftMargin: 16
            anchors.top: parent.top
            anchors.topMargin: 20
        }
    }

    Rectangle {
        color: "#e0e0e0"
        anchors.top: header.bottom
        anchors.bottom: parent.bottom
        anchors.left: parent.left
        anchors.right: parent.right

        RowLayout {
            anchors.verticalCenter: parent.verticalCenter
            anchors.horizontalCenter: parent.horizontalCenter
            spacing: 48

            IconLabel {
                text: MdiFont.Icon.cloud
            }

            IconLabel {
                text: MdiFont.Icon.lambda
            }

            IconLabel {
                text: MdiFont.Icon.signCaution
            }

            IconLabel {
                text: MdiFont.Icon.recycle
            }
        }
    }
}

To keep things clean, consistent, and DRY, I banished the basic formatting details to my customized IconLabel element:

IconLabel.qml

import QtQuick 2.7

Text {
    font.family: "Material Design Icons"
    font.pixelSize: 96
    opacity: 0.75
}

With this technique, you can deliver an authentic look and feel in your Qt apps that target the Android platform. You can download the JavaScript object mentioned earlier from my GitHub project. I've made the file available under the terms of the SIL Open Font License, version 1.1, to match the license of the Material Design Icons font.


Lead image is a screenshot of a sample QML application with Material Design icons. Wallpaper image © 2012 by Flickr user Hemlit, released under the Creative Commons Attribution 2.0 Generic License. Wallpaper is available here. Icon choices not intended to confirm Half-Life 3.