What is QML?
QML (Qt Modeling Language) is a declarative language for designing fluid, animated UIs. It is ideal for:
- Embedded HMI — dashboards, touch interfaces
- Modern desktop apps — animated, GPU-accelerated UIs
- Rapid prototyping — visual results without recompiling C++
QML handles the view layer; C++ handles logic and data.
Your First QML File
// Main.qml
import QtQuick 6.0
import QtQuick.Controls 6.0
ApplicationWindow {
id: root
visible: true
width: 480
height: 320
title: "EmbeddexAI — QML Demo"
Rectangle {
anchors.fill: parent
color: "#1e1e2e"
Column {
anchors.centerIn: parent
spacing: 20
Text {
text: "Hello from QML"
color: "#cdd6f4"
font.pixelSize: 28
font.bold: true
anchors.horizontalCenter: parent.horizontalCenter
}
Button {
text: "Click Me"
anchors.horizontalCenter: parent.horizontalCenter
onClicked: label.text = "Button clicked!"
}
Text {
id: label
text: "Waiting..."
color: "#a6e3a1"
font.pixelSize: 16
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
}
Loading QML from C++
// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl("qrc:/qml/Main.qml"));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
CMakeLists.txt — add QML module:
find_package(Qt6 REQUIRED COMPONENTS Quick Qml)
qt_add_qml_module(MyApp
URI MyApp
VERSION 1.0
QML_FILES
qml/Main.qml
qml/Dashboard.qml
)
target_link_libraries(MyApp PRIVATE Qt6::Quick Qt6::Qml)
QML Layout & Anchors
QML uses an anchor system for positioning:
Rectangle {
width: 200; height: 100
color: "#313244"
radius: 8
Text {
anchors.centerIn: parent // center in parent
text: "Centered"
color: "white"
}
Rectangle {
anchors.top: parent.top // stick to top
anchors.right: parent.right // stick to right
anchors.margins: 8
width: 12; height: 12
color: "#f38ba8"
radius: 6
}
}
Use RowLayout, ColumnLayout, GridLayout from QtQuick.Layouts:
import QtQuick.Layouts 6.0
RowLayout {
spacing: 12
Button { text: "A"; Layout.fillWidth: true }
Button { text: "B"; Layout.fillWidth: true }
Button { text: "C"; Layout.preferredWidth: 80 }
}
Animations
Rectangle {
id: box
width: 60; height: 60
color: "#89b4fa"
radius: 8
// Property animation
NumberAnimation on x {
from: 0; to: 400
duration: 1000
easing.type: Easing.InOutQuad
loops: Animation.Infinite
}
// Behavior — animate any change to opacity
Behavior on opacity {
NumberAnimation { duration: 300 }
}
MouseArea {
anchors.fill: parent
onClicked: box.opacity = box.opacity < 1 ? 1.0 : 0.3
}
}
State-based animations:
Rectangle {
id: indicator
width: 100; height: 100
color: "gray"
states: [
State { name: "active"; PropertyChanges { target: indicator; color: "#a6e3a1" } },
State { name: "error"; PropertyChanges { target: indicator; color: "#f38ba8" } }
]
transitions: Transition {
ColorAnimation { duration: 400 }
}
MouseArea {
anchors.fill: parent
onClicked: indicator.state = (indicator.state === "active") ? "error" : "active"
}
}
Exposing C++ to QML
Method 1 — Register a QObject as Context Property
// backend.h
class Backend : public QObject {
Q_OBJECT
Q_PROPERTY(float temperature READ temperature NOTIFY temperatureChanged)
public:
float temperature() const { return m_temp; }
public slots:
void readSensor() { m_temp = 36.5f; emit temperatureChanged(m_temp); }
signals:
void temperatureChanged(float temp);
private:
float m_temp = 0.0f;
};
// main.cpp
Backend backend;
engine.rootContext()->setContextProperty("backend", &backend);
engine.load(QUrl("qrc:/qml/Main.qml"));
// Main.qml
Text {
text: "Temp: " + backend.temperature.toFixed(1) + " °C"
}
Button {
text: "Read"
onClicked: backend.readSensor()
}
Method 2 — Register as QML Type
// In main.cpp before engine.load()
qmlRegisterType<Backend>("com.embeddexai", 1, 0, "Backend");
import com.embeddexai 1.0
Backend { id: backend }
Text { text: backend.temperature.toFixed(1) + " °C" }
ListView with C++ Model
// sensormodel.h
class SensorModel : public QAbstractListModel {
Q_OBJECT
public:
enum Roles { NameRole = Qt::UserRole + 1, ValueRole };
// ... implement rowCount, data, roleNames
};
ListView {
width: 300; height: 400
model: sensorModel // set via context property
delegate: Rectangle {
width: ListView.view.width
height: 48
color: index % 2 === 0 ? "#313244" : "#1e1e2e"
Row {
anchors { left: parent.left; leftMargin: 16; verticalCenter: parent.verticalCenter }
spacing: 16
Text { text: model.name; color: "#cdd6f4" }
Text { text: model.value; color: "#a6e3a1" }
}
}
}
Summary
| Concept | Key Point |
|---|---|
| QML | Declarative language for UI |
| Qt Quick | QML component library (Rectangle, Text, etc.) |
| Anchors | Flexible, resolution-independent positioning |
| Animations | NumberAnimation, Behavior, State/Transition |
| C++ integration | setContextProperty or qmlRegisterType |
| QML + C++ | QML = view, C++ = logic and data |
Next tutorial → Model/View Architecture