30 Mar 2018
Using FontAwesome 5 in QML
FontAwesome is a set of icon fonts making it easy to beef up your user interfaces. It is mostly used in web applications (aka HTML/CSS), however, leveraging it to your Qt applications is not difficult either.
First, download the latest Desktop release from their website. You unzip it and find the contained *.otf
files in otfs
folder. You should have the following files there:
Font Awesome 5 Brands-Regular-400.otf
Font Awesome 5 Free-Regular-400.otf
Font Awesome 5 Free-Solid-900.otf
Copy these into your application’s source directory.
Note: Make sure you use a recent version of FontAwesome 5. Earlier releases had an issue which prevented you to use both the solid and regular variants. This issue is meanwhile gone for the OTF files. Also, you still will encounter the issue when using the TTF files, but as Qt/QML can deal with both, just make sure you pick the OTF version from the Desktop release.
In QML, we can now easily access these fonts by writing a (singleton) component which makes them available:
// Fonts.qml
pragma Singleton
import QtQuick 2.0
Item {
id: fonts
readonly property FontLoader fontAwesomeRegular: FontLoader {
source: "./Font Awesome 5 Free-Regular-400.otf"
}
readonly property FontLoader fontAwesomeSolid: FontLoader {
source: "./Font Awesome 5 Free-Solid-900.otf"
}
readonly property FontLoader fontAwesomeBrands: FontLoader {
source: "./Font Awesome 5 Brands-Regular-400.otf"
}
readonly property string icons: fonts.fontAwesomeRegular.name
readonly property string brands: fonts.fontAwesomeBrands.name
}
For the singleton to work, you must create a qmldir
file next to it as well:
// qmldir
singleton Fonts 1.0 Fonts.qml
With this, you should be able to display some icons using e.g. a ToolButton
:
// FontAwesomeToolButton.qml
import QtQuick 2.9
import QtQuick.Controls 2.2
// This must point to the directory where you placed
// the 'Fonts.qml' file. If all your sources are in the
// same directory, this can be '.' as well.
import "../path/to/Fonts"
ToolButton {
id: button
property alias symbol: button.text
// This can be set to either Fonts.icons or Fonts.brands
// to switch between the two icon sets.
font.family: Fonts.solidIcons
// This controls the style of the regular icons which is
// used. The default value (Regular) will map to the regular
// icon set. Use either Font.Bold or Font.Light to switch
// to the other styles.
font.weight: Font.Regular
}
And finally we can use our tool button implementation:
// demo.qml
import QtQuick 2.9
// Adjust the paths accordingly. The latter import is where
// our tool button implementation is stored:
import "./path/to/Fonts"
import "./path/to/Components"
Grid {
columns: 3
FontAwesomeToolButton {
symbol: "\uf2bb"
}
FontAwesomeToolButton {
symbol: "\uf556"
}
FontAwesomeToolButton {
symbol: "\uf35b"
}
FontAwesomeToolButton {
symbol: "\uf2bb"
font.weight: Font.Bold
}
FontAwesomeToolButton {
symbol: "\uf556"
font.weight: Font.Bold
}
FontAwesomeToolButton {
symbol: "\uf35b"
font.weight: Font.Bold
}
FontAwesomeToolButton {
symbol: "\uf270"
}
FontAwesomeToolButton {
symbol: "\uf294"
}
FontAwesomeToolButton {
symbol: "\uf268"
}
}
Run this e.g. via qmlscene
:
You should get something like this:
While this approach works, you will have notices one bad thing: In order to select which icon to display, we inserted the unicode character codes as label names. You can get them easily from the FontAwesome Gallery, however, after inserting into the QML source code you do not quickly see which icon a code refers to. In HTML, you would use something like
<i class="fas fa-anchor"></i>
<i class="fas fa-angle-double-right"></i>
<i class="fas fa-asterisk"></i>
which is far more readable. To achieve something similar in QML, we can extract some meta information from the FontAwesome download package and generate another QML component from that one.
First, create a file fa_iconsjson2qml.py
and put the following content in it:
#!/bin/env python3
"""
Convert FontAwesome's `icons.json` to QML.
This script creates a QML component which defines
constants for all FontAwesome icons listed in the file
`icons.json` in the FontAwesome package.
"""
import sys
def _dash2cap(name):
try:
while True:
idx = name.index("-")
pre = name[0:idx]
suf = name[idx + 2:]
cap = name[idx + 1:idx + 2].capitalize()
name = pre + cap + suf
except ValueError:
pass
return name
def _main(argv):
import json
if len(argv) != 3:
print("Usage:")
msg = " {} path/to/icons.json path/to/Icons.qml"
msg = msg.format(argv[0])
print(msg)
sys.exit(1)
with open(argv[1], "r") as file:
icons = json.load(file)
lines = []
lines.append("pragma Singleton")
lines.append("import QtQuick 2.0")
lines.append("")
lines.append("QtObject {")
prop = ' readonly property string {}: "{}"'
for key in icons:
name = "fa-" + key
name = _dash2cap(name)
code = "\\u" + icons[key]["unicode"]
line = prop.format(name, code)
lines.append(line)
lines.append("}")
with open(argv[2], "w") as file:
file.write("\n".join(lines))
if __name__ == '__main__':
_main(sys.argv)
Make the file executable and call it on the file icons.json
which is contained in the FontAwesome zip:
chmod +x ./fa_iconsjson2qml.py
./fa_iconsjson2qml.py \
./path/to/FontAwesome/metadata/icons.json \
./path/to/qml/sources/Fonts/Icons.qml
This script basically extracts the available icons from the JSON file and creates another QML singleton component which looks like this:
pragma Singleton
import QtQuick 2.0
QtObject {
readonly property string fa500px: "\uf26e"
readonly property string faAccessibleIcon: "\uf368"
readonly property string faAccusoft: "\uf369"
readonly property string faAddressBook: "\uf2b9"
readonly property string faAddressCard: "\uf2bb"
// several hundred similar lines following...
}
Ideally, put the file next to the Fonts.qml
file and edit the qmldir
file to look like this:
singleton Icons 1.0 Icons.qml
singleton Fonts 1.0 Fonts.qml
Now, you can modify the demo from above to:
// demo.qml
import QtQuick 2.9
// Adjust the paths accordingly. The latter import is where
// our tool button implementation is stored:
import "./path/to/Fonts"
import "./path/to/Components"
Grid {
columns: 3
FontAwesomeToolButton {
symbol: Icons.faAddressCard
}
FontAwesomeToolButton {
symbol: Icons.faAngry
}
FontAwesomeToolButton {
symbol: Icons.faArrowAltCircleUp
}
FontAwesomeToolButton {
symbol: Icons.faAddressCard
font.weight: Font.Bold
}
FontAwesomeToolButton {
symbol: Icons.faAngry
font.weight: Font.Bold
}
FontAwesomeToolButton {
symbol: Icons.faArrowAltCircleUp
font.weight: Font.Bold
}
FontAwesomeToolButton {
symbol: Icons.faAmazon
}
FontAwesomeToolButton {
symbol: Icons.faBluetoothB
}
FontAwesomeToolButton {
symbol: Icons.faChrome
}
}
… which is way more readable.
Thank You For Reading
I am a software/firmware developer, working in Dresden, Germany. In my free time, I spent some time on developing apps, presenting some interesting findings here in my blog.
Comments