Advanced Text Rendering and Layout Techniques in QML
This guide demonstrates practical implementations for dynamic text presentation, typographic control, and automated layout distribution within the QML ecosystem. Each segment focuses on a specific rendering mechanism, providing optimized code structures for production environments.
Animated Character Spacing and Opacity Fades
Creating synchronized transition effects often requires managing multiple property animations simultaneously. The following implementation pairs letter-spacing expansion with an opacity fade, using independent sequential chains that share an identical cycle duration. Upon completion, a script action randomizes the element's position for continuous looping.
import QtQuick 2.0
Rectangle {
id: mainCanvas
width: 320; height: 480
color: "#000000"
Item {
id: positionHolder
x: mainCanvas.width / 2
y: mainCanvas.height / 2
Text {
id: displayLabel
anchors.centerIn: parent
color: "#FFFFFF"
text: "Hello world!"
font.pixelSize: 32
SequentialAnimation on font.letterSpacing {
loops: Animation.Infinite
NumberAnimation {
from: 0; to: 50
easing.type: Easing.InQuad
duration: 3000
}
ScriptAction {
script: {
positionHolder.y = (mainCanvas.height / 4) + (Math.random() * mainCanvas.height / 2);
positionHolder.x = (mainCanvas.width / 4) + (Math.random() * mainCanvas.width / 2);
}
}
}
SequentialAnimation on opacity {
loops: Animation.Infinite
NumberAnimation { from: 1; to: 0; duration: 2600 }
PauseAnimation { duration: 400 }
}
}
}
}
Dynamic Font Loading and Typography Controls
QML provides the FontLoader component to asynchronously load system, local, or remote typefaces. Once resolved, the loaded family name can be bound to font.family. Combined with built-in properties like capitalization, weight, and italic, developers can achieve complex stylistic variations without external assets.
import QtQuick 2.0
Rectangle {
property string sampleContent: "The quick brown fox jumps over the lazy dog."
width: 320; height: 480
color: "#4682B4"
FontLoader { id: monospaceSource; name: "Courier New" }
FontLoader { id: assetFont; source: "content/fonts/custom.otf" }
FontLoader { id: remoteFont; source: "https://cdn.example.com/fonts/webfont.ttf" }
Column {
anchors.fill: parent
anchors.margins: 10
spacing: 15
Text {
text: sampleContent
color: "#B0C4DE"
width: parent.width
wrapMode: Text.WordWrap
font.family: "Georgia"
font.pixelSize: 20
}
Text {
text: sampleContent
color: "#B0C4DE"
width: parent.width
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
font.family: "Georgia"; font.pixelSize: 20
font.capitalization: Font.AllUppercase
}
Text {
text: sampleContent
color: "#B0C4DE"
width: parent.width
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignRight
font.family: monospaceSource.name
font.pixelSize: 20
font.weight: Font.Bold
font.capitalization: Font.Lowercase
}
Text {
text: sampleContent
color: "#B0C4DE"
width: parent.width
wrapMode: Text.WordWrap
font.family: monospaceSource.name
font.pixelSize: 20
italic: true
font.capitalization: Font.SmallCaps
}
Text {
text: sampleContent
color: "#B0C4DE"
width: parent.width
wrapMode: Text.WordWrap
font.family: assetFont.name
font.pixelSize: 20
font.capitalization: Font.Capitalize
}
Text {
text: {
if (remoteFont.status === FontLoader.Ready) return sampleContent
if (remoteFont.status === FontLoader.Loading) return "Fetching resource..."
return "Font unavailable"
}
color: "#B0C4DE"
width: parent.width
wrapMode: Text.WordWrap
font.family: remoteFont.name
font.pixelSize: 20
}
}
}
Enumerating Installed System Typefaces
The QML engine exposes a runtime list of installed fonts through Qt.fontFamilies(). Binding this data source to a ListView enables immediate visualization of available typography, with the modelData role serving both as the displayed name and the applied font family.
import QtQuick 2.0
Rectangle {
width: 320; height: 480
color: "#4682B4"
ListView {
anchors.fill: parent
model: Qt.fontFamilies()
delegate: Item {
height: 40
width: ListView.view.width
Text {
anchors.centerIn: parent
text: modelData
font.family: modelData
font.pixelSize: 20
color: "#FFFFFF"
}
}
}
}
Inline HTML-like Styling and Embedded Media
QML supports a subset of CSS3 and HTML markup within Text components. Tags such as <b> and <i> handle emphasis, while <img> allows direct embedding of raster assets. Inline attributes control alignment, scaling, and vertical positioning relative to the baseline.
import QtQuick 2.0
Rectangle {
id: uiContainer
width: 320; height: 480
focus: true
color: "#DEDEDE"
property int hAlignMode: Text.AlignLeft
Flickable {
anchors.fill: parent
contentWidth: parent.width
contentHeight: contentStack.height + 20
Column {
id: contentStack
x: 10; y: 10
spacing: 20
width: parent.width - 20
RichTextBlock {
text: "This is a <b>joyful</b> face<img src="\"assets/smile.png\""></img>"
}
RichTextBlock {
text: "A vertically <b>centered<img align="\"middle\"/" src="\"assets/big-smile.png\""></img>expression</b>."
}
RichTextBlock {
text: "Compact icon overlay<img height="\"16\"" src="\"assets/smile.png\"" width="\"16\""></img>integrated seamlessly."
}
RichTextBlock {
text: "Top-aligned<img align="\"top\"" height="\"50\"" src="\"assets/starfish.png\"" width="\"50\""></img>with corresponding bottom-aligned<img height="\"50\"" src="\"assets/heart.png\"" width="\"50\""></img>markers."
}
RichTextBlock {
text: "Multi-size branding<img align="\"middle\"" height="\"60\"" src="\"assets/logo-main.png\"" width="\"55\""></img><img align="\"middle\"" height="\"40\"" src="\"assets/logo-alt.png\"" width="\"37\""></img><img align="\"middle\"" height="\"20\"" src="\"assets/logo-mini.png\"" width="\"18\""></img>stacked horizontally."
}
RichTextBlock {
text: "Variable scale heart icons<img align="\"bottom\"" height="\"20\"" src="\"assets/heart.png\"" width="\"20\""></img><img align="\"bottom\"" height="\"30\"" src="\"assets/heart.png\"" width="\"30\""></img><img height="\"40\"" src="\"assets/heart.png\"" width="\"40\""></img><img align="\"bottom\"" height="\"50\"" src="\"assets/heart.png\"" width="\"50\""></img>rendered dynamically."
}
RichTextBlock {
text: "Externally hosted asset<img align="\"middle\"" height="\"48\"" src="\"https://external.cdn.net/image.png\"" width="\"48\""></img>loaded at runtime."
}
RichTextBlock {
verticalAlignment: Text.AlignVCenter
text: "Explicit height constraint ensuring stable baseline alignment for <b>mixed media</b> content."
}
}
}
Keys.onUpPressed: uiContainer.hAlignMode = Text.AlignHCenter
Keys.onLeftPressed: uiContainer.hAlignMode = Text.AlignLeft
Keys.onRightPressed: uiContainer.hAlignMode = Text.AlignRight
}
Flow-Based Multi-Column Line Distribution
For responsive documentation or lengthy content blocks, automatic column wrapping prevents manual overflow handling. By listening too the onLineLaidOut signal, developers can intercept individual line metrics. When a line exceeds the vertical boundary, its coordinates are redirected to a secondary column region, effectively creating a newspaper-style flow.
import QtQuick 2.0
Rectangle {
id: scrollArea
width: 320; height: 480
focus: true
property real columnGap: 8
Text {
id: flowLabel
anchors.fill: parent
anchors.margins: 10
wrapMode: Text.WordWrap
font.family: "Times New Roman"
font.pixelSize: 14
textFormat: Text.StyledText
horizontalAlignment: Text.AlignJustify
text: "<a href="\"http://example.com\"">Documentation Link</a>. <br></br>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at ante dui.<ul type="\"bullet\""><li>Coffee<br></br><ol type="\"a\""><li>Espresso</li><li>Cappuccino</li></ol></li></ul><font color="\"#333333\""><i>Advanced typography <b>engine</b> demonstration featuring dynamic redistribution.</i></font>"
onLineLaidOut: {
line.width = width / 2 - columnGap
if (line.y + line.height >= height) {
line.y -= height - columnGap
line.x = width / 2 + columnGap
}
}
}
}