QML
QML
#qml
Table of Contents
About 1
Remarks 2
Versions 2
Examples 2
Installation 2
Hello World 3
Display an image 4
Mouse Event 4
Chapter 2: Animation 6
Examples 6
Examples 8
Examples 12
Remarks 24
Examples 24
Credits 26
About
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: qml
It is an unofficial and free qml ebook created for educational purposes. All the content is extracted
from Stack Overflow Documentation, which is written by many hardworking individuals at Stack
Overflow. It is neither affiliated with Stack Overflow nor official qml.
The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/ 1
Chapter 1: Getting started with qml
Remarks
QML is an acronym that stands for Qt Meta-object Language. It is a declarative programming
language that is part of the Qt framework. QML's main purpose is fast and easy creation of user
interfaces for desktop, mobile and embedded systems. QML allows seamless integration of
JavaScript, either directly in the QML code or by including JavaScript files.
Versions
Examples
Installation
QML comes with newer Version of the cross-platform application framework Qt. You can find the
newest Version of Qt in the Downloads section.
To create a new QML Project in the Qt Creator IDE, select "File -> New ..." and under
"Applications" select "Qt Quick-Application". After clicking "select" you can now name and set the
path for this project. After hitting "next" you can select which components you want to use, if
https://riptutorial.com/ 2
unsure just leave the default and click on "next". The two next steps will allow you to setup up a Kit
and Source Control if you want to, otherwise keep the default settings.
You now have created a simple and ready to use QML application.
Hello World
A simple application showing the text "Hello World" in the center of the window.
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World") //The method qsTr() is used for translations from one language
to other.
Text {
text: qsTr("Hello World")
anchors.centerIn: parent
}
}
You can easily transform every component in a clickable button using the MouseArea component.
The code below displays a 360x360 window with a button and a text in the center; pressing the
button will change the text:
Rectangle {
width: 360
height: 360
Rectangle {
id: button
width: 100
height: 30
color: "red"
radius: 5 // Let's round the rectangle's corner a bit, so it resembles more a
button
anchors.centerIn: parent
Text {
id: buttonText
text: qsTr("Button")
color: "white"
anchors.centerIn: parent
}
MouseArea {
// We make the MouseArea as big as its parent, i.e. the rectangle. So pressing
https://riptutorial.com/ 3
anywhere on the button will trigger the event
anchors.fill: parent
Display an image
This example shows the simplest usage of the Image component to display an image.
The Image source property is a url type that can be either a file with an absolute or relative path, an
internet URL (http://) or a Qt resource (qrc:/)
Rectangle {
width: 640
height: 480
Image {
source: "image.png"
}
}
Mouse Event
Window {
visible: true
Rectangle {
anchors.fill: parent
width: 120; height: 240
color: "#4B7A4A"
MouseArea {
anchors.fill: parent // set mouse area (i.e. covering the entire rectangle.)
acceptedButtons: Qt.AllButtons
onClicked: {
// print to console mouse location
console.log("Mouse Clicked.")
console.log("Mouse Location: <",mouseX,",",mouseY,">")
https://riptutorial.com/ 4
if ( mouse.button === Qt.RightButton )
parent.color = 'blue'
if ( mouse.button === Qt.LeftButton )
parent.color = 'red'
if ( mouse.button === Qt.MiddleButton )
parent.color = 'yellow'
}
onReleased: {
// print to console
console.log("Mouse Released.")
}
onDoubleClicked: {
// print to console
console.log("Mouse Double Clicked.")
}
}
}
https://riptutorial.com/ 5
Chapter 2: Animation
Examples
Simple number animation
One of the very basic animations that you could come across is the NumberAnimation. This
animation works by changing the numeric value of a property of an item from an initial state to a
final state. Consider the following complete example:
ApplicationWindow {
visible: true
width: 400
height: 640
Rectangle{
id: rect
anchors.centerIn: parent
height: 100
width: 100
color: "blue"
MouseArea{
anchors.fill: parent
onClicked: na.running = true
}
NumberAnimation {
id: na //ID of the QML Animation type
target: rect //The target item on which the animation should run
property: "height" //The property of the target item which should be changed by
the animator to show effect
duration: 200 //The duration for which the animation should run
from: rect.height //The initial numeric value of the property declared in
'property'
to: 200 //The final numeric value of the property declared in 'property'
}
}
}
A behavior based animation allows you to specify that when a property changes the change
should be animated over time.
ProgressBar {
id: progressBar
from: 0
to: 100
Behavior on value {
NumberAnimation {
https://riptutorial.com/ 6
duration: 250
}
}
}
In this example if anything changes the progress bar value the change will be animated over
250ms
https://riptutorial.com/ 7
Chapter 3: Creating custom elements in C++
Examples
Creating custom elements in C++
QML came with rich set of visual elements. Using only QML we can build complex applications
with these elements. Also it's very easy to build your own element based on set of standard items
like Rectangle, Button, Image etc. Moreover, we can use items like Canvas to build element with
custom painting. It would seem that we can build a variety of applications in QML only, without
touching the capabilities of C++. And it's actually true but still sometimes we would like to make
our application faster or we want to extend it with power of Qt or to add some opportunity which
are not available in QML. And certainly there is such possibility in QML. Basically QtQuick uses
Scene Graph to paint its content a high-performance rendering engine based on OpenGL. To
implement our own visual element we can use 2 ways:
It is possible that the first method seems easier but it's worth considering that it is also slower than
the first one since QtQuick paints the item's content on a surface and then insert it into scene
graph so the rendering is a two-step operation. So using scene graph API directly is always
significantly faster.
In order to explore both methods closer let's create our own element which definitely doesn't exist
in QML, for example a triangle.
Class declaration
protected:
QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData);
private:
QColor m_color;
bool m_needUpdate;
signals:
void colorChanged();
};
https://riptutorial.com/ 8
We add Q_OBJECT macro to work with signals. Also we add custom property to specify color of
our Rectangle. To make it works all we need is reimplement virtual function
QQuiclItem::updatePaintNode().
Class implementation.
QQuickCustomItem::QQuickCustomItem(QQuickItem *parent) :
QQuickItem(parent),
m_color(Qt::red),
m_needUpdate(true)
{
setFlag(QQuickItem::ItemHasContents);
}
Please note that the setFlag() function call is mandatory otherwise your object will not be added to
the scene graph. Next, we define a function for the paining.
if(!root) {
root = new QSGGeometryNode;
QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 3);
geometry->setDrawingMode(GL_TRIANGLE_FAN);
geometry->vertexDataAsPoint2D()[0].set(width() / 2, 0);
geometry->vertexDataAsPoint2D()[1].set(width(), height());
geometry->vertexDataAsPoint2D()[2].set(0, height());
root->setGeometry(geometry);
root->setFlag(QSGNode::OwnsGeometry);
root->setFlag(QSGNode::OwnsMaterial);
}
if(m_needUpdate) {
QSGFlatColorMaterial *material = new QSGFlatColorMaterial;
material->setColor(m_color);
root->setMaterial(material);
m_needUpdate = false;
}
return root;
}
At the first call to the function our node isn't created yet so oldNode will be NULL. So we create the
node and assign geometry and material to it. Here we use GL_TRIANGLE_FAN for our geometry
to paint solid rectangle. This point is the same as in OpenGL. For example to draw triangle frame
we can change the code to:
geometry->setDrawingMode(GL_LINE_LOOP);
geometry->setLineWidth(5);
https://riptutorial.com/ 9
You can refer to OpenGL manual to check for other shapes. So, all that remains is to define
setter/getter for our property:
Now there is only one small detail to make it works. We need to notify QtQuick of the new item.
For example, you can add this code to your main.cpp:
qmlRegisterType<QQuickCustomItem>("stackoverflow.qml", 1, 0, "Triangle");
Window {
width: 800
height: 800
visible: true
Rectangle {
width: 200
height: 200
anchors.centerIn: parent
color: "lightgrey"
Triangle {
id: rect
width: 200
height: 200
transformOrigin: Item.Top
color: "green"
onColorChanged: console.log("color was changed");
PropertyAnimation on rotation {
from: 0
to: 360
duration: 5000
loops: Animation.Infinite
}
}
}
Timer {
interval: 1000
https://riptutorial.com/ 10
repeat: true
running: true
onTriggered: rect.color = Qt.rgba(Math.random(),Math.random(),Math.random(),1);
}
}
As you see our item behaves like all other QML items. Now let's create the same item using
QPainter:
with
and, of cource inherit our class from QQuickPaintedItem instead of QQuickItem. Here is our painting
function:
https://riptutorial.com/ 11
Chapter 4: Integration with C++
Examples
Creating a QtQuick view from C++
It is possible to create a QtQuick view directly from C++ and to expose to QML C++ defined
properties. In the code below the C++ program creates a QtQuick view and exposes to QML the
height and width of the view as properties.
main.cpp
#include <QApplication>
#include <QQmlContext>
#include <QQuickView>
// Creating the view and manually setting the QML file it should display
QQuickView view;
view.setSource(QStringLiteral("main.qml"));
// Retrieving the QML context. This context allows us to expose data to the QML components
QQmlContext* rootContext = view.rootContext();
return app.exec();
}
main.qml
Rectangle {
// We can now access the properties we defined from C++ from the whole QML file
width: WINDOW_WIDTH
height: WINDOW_HEIGHT
Text {
text: qsTr("Hello World")
anchors.centerIn: parent
}
}
https://riptutorial.com/ 12
As of Qt 5.1 and later you can use QQmlApplicationEngine instead of QQuickView to load and
render a QML script.
With QQmlApplicationEngine you do need to use a QML Window type as your root element.
You can obtain the root context from the engine where you can then add global properties to the
context which can be access by the engine when processing QML scripts.
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
main.qml
MouseArea {
anchors.fill: parent
onClicked: {
Qt.quit();
}
}
Text {
text: qsTr("Hello World")
anchors.centerIn: parent
}
}
https://riptutorial.com/ 13
Creating a simple model for TreeView
Since Qt 5.5 we have a new wonderful TreeView, a control we've all been waiting for. A TreeView
implements a tree representation of items from a model. In general it looks like other QML views -
ListView or TableView. But data structure of TreeView is more complex.
Another major difference is that TreeView doesn't support ListModel. To provide a data we must
subclass QAbstractItemModel. In Qt there are ready to use model classes like QFileSystemModel
which provides access to local file system, or QSqlTableModel which provides access to a data
base.
In following example we will create such model derived from QAbstractItemModel. But to make the
example more realistic I suggest to make the model like ListModel but specified for trees so we
can add nodes from QML. It's necessary to clarify that model itself doesn't contain any data but
only provide access to it. So providing and organization of data is entirely our responsibility.
Since model data is organized in a tree the simplest node structure is seen as follows, in pseudo
code:
Node {
var data;
Node parent;
list<Node> children;
}
private:
QList<MyTreeNode *> m_nodes;
MyTreeNode *m_parentNode;
https://riptutorial.com/ 14
};
We derive our class from QObject to be able to create a node in QML. All the children nodes will be
added to nodes property so next 2 part of code are the same:
TreeNode {
nodes:[
TreeNode {}
TreeNode {}
]
}
TreeNode {
TreeNode {}
TreeNode {}
}
MyTreeNode::MyTreeNode(QObject *parent) :
QObject(parent),
m_parentNode(nullptr) {}
QQmlListProperty<MyTreeNode> MyTreeNode::nodes()
{
QQmlListProperty<MyTreeNode> list(this,
0,
&append_element,
&count_element,
&at_element,
&clear_element);
return list;
}
void MyTreeNode::clear()
{
qDeleteAll(m_nodes);
m_nodes.clear();
}
https://riptutorial.com/ 15
bool MyTreeNode::insertNode(MyTreeNode *node, int pos)
{
if(pos > m_nodes.count())
return false;
if(pos < 0)
pos = m_nodes.count();
m_nodes.insert(pos, node);
return true;
}
childNode->setParentNode(parentElement);
https://riptutorial.com/ 16
beginInsertRows(parent, pos, pos);
bool retValue = parentElement->insertNode(childNode, pos);
endInsertRows();
return retValue;
}
https://riptutorial.com/ 17
Q_DECL_OVERRIDE;
QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QQmlListProperty<MyTreeNode> nodes();
protected:
MyTreeNode *getNode(const QModelIndex &index) const;
private:
MyTreeNode *m_rootNode;
QHash<int, QByteArray> m_roles;
signals:
void rolesChanged();
};
Since we derived out model class from abstract QAbstractItemModel we must redefine next
function: data(), flags(), index(), parent(), columnCount() and rowCount(). In order our model could
work with QML we define roleNames(). Also, as well as in node class we define default property to
be able to add nodes to the model in QML. roles property will hold a list of role names.
The implementation:
MyTreeModel::MyTreeModel(QObject *parent) :
QAbstractItemModel(parent)
{
m_rootNode = new MyTreeNode(nullptr);
}
MyTreeModel::~MyTreeModel()
{
delete m_rootNode;
}
https://riptutorial.com/ 18
{
if (!index.isValid())
return 0;
return QAbstractItemModel::flags(index);
}
if (parentItem == m_rootNode)
return QModelIndex();
QQmlListProperty<MyTreeNode> MyTreeModel::nodes()
{
return m_rootNode->nodes();
}
https://riptutorial.com/ 19
return list;
}
childNode->setParentNode(parentElement);
beginInsertRows(parent, pos, pos);
bool retValue = parentElement->insertNode(childNode, pos);
endInsertRows();
return retValue;
}
https://riptutorial.com/ 20
return m_rootNode;
}
In general, this code it's not much different from the standard implementation, for example Simple
tree example
Instead of defining roles in C++ we provide a way to do that from QML. TreeView events and
methods basically work with QModelIndex. I personally don't see much sense to pass that to qml
as the only thing you can do with it is to pass it back to the model.
Anyway, our class provides a way to convert index to node and vice versa. To be able to use our
classes in QML we need to register it:
qmlRegisterType<MyTreeModel>("qt.test", 1, 0, "TreeModel");
qmlRegisterType<MyTreeNode>("qt.test", 1, 0, "TreeElement");
And finelly, en example of how we can use our model with TreeView in QML:
Window {
visible: true
width: 800
height: 800
title: qsTr("Tree example")
Component {
id: fakePlace
TreeElement {
property string name: getFakePlaceName()
property string population: getFakePopulation()
property string type: "Fake place"
function getFakePlaceName() {
var rez = "";
for(var i = 0;i < Math.round(3 + Math.random() * 7);i ++) {
rez += String.fromCharCode(97 + Math.round(Math.random() * 25));
}
return rez.charAt(0).toUpperCase() + rez.slice(1);
}
function getFakePopulation() {
var num = Math.round(Math.random() * 100000000);
num = num.toString().split("").reverse().join("");
num = num.replace(/(\d{3})/g, '$1,');
num = num.split("").reverse().join("");
return num[0] === ',' ? num.slice(1) : num;
}
}
}
TreeModel {
id: treemodel
roles: ["name","population"]
https://riptutorial.com/ 21
TreeElement {
property string name: "Asia"
property string population: "4,164,252,000"
property string type: "Continent"
TreeElement {
property string name: "China";
property string population: "1,343,239,923"
property string type: "Country"
TreeElement { property string name: "Shanghai"; property string population:
"20,217,700"; property string type: "City" }
TreeElement { property string name: "Beijing"; property string population:
"16,446,900"; property string type: "City" }
TreeElement { property string name: "Chongqing"; property string population:
"11,871,200"; property string type: "City" }
}
TreeElement {
property string name: "India";
property string population: "1,210,193,422"
property string type: "Country"
TreeElement { property string name: "Mumbai"; property string population:
"12,478,447"; property string type: "City" }
TreeElement { property string name: "Delhi"; property string population:
"11,007,835"; property string type: "City" }
TreeElement { property string name: "Bengaluru"; property string population:
"8,425,970"; property string type: "City" }
}
TreeElement {
property string name: "Indonesia";
property string population: "248,645,008"
property string type: "Country"
TreeElement {property string name: "Jakarta"; property string population:
"9,588,198"; property string type: "City" }
TreeElement {property string name: "Surabaya"; property string population:
"2,765,487"; property string type: "City" }
TreeElement {property string name: "Bandung"; property string population:
"2,394,873"; property string type: "City" }
}
}
TreeElement { property string name: "Africa"; property string population:
"1,022,234,000"; property string type: "Continent" }
TreeElement { property string name: "North America"; property string population:
"542,056,000"; property string type: "Continent" }
TreeElement { property string name: "South America"; property string population:
"392,555,000"; property string type: "Continent" }
TreeElement { property string name: "Antarctica"; property string population: "4,490";
property string type: "Continent" }
TreeElement { property string name: "Europe"; property string population:
"738,199,000"; property string type: "Continent" }
TreeElement { property string name: "Australia"; property string population:
"29,127,000"; property string type: "Continent" }
}
TreeView {
anchors.fill: parent
model: treemodel
TableViewColumn {
title: "Name"
role: "name"
width: 200
}
TableViewColumn {
https://riptutorial.com/ 22
title: "Population"
role: "population"
width: 200
}
onDoubleClicked: {
var element = fakePlace.createObject(treemodel);
treemodel.insertNode(element, index, -1);
}
onPressAndHold: {
var element = treemodel.getNodeByIndex(index);
messageDialog.text = element.type + ": " + element.name + "\nPopulation: " +
element.population;
messageDialog.open();
}
}
MessageDialog {
id: messageDialog
title: "Info"
}
}
Double click for adding a node, press and hold for node info.
https://riptutorial.com/ 23
Chapter 5: Property binding
Remarks
An object's property can be assigned a static value which stays constant until it is explicitly
assigned a new value. However, to make the fullest use of QML and its built-in support for
dynamic object behaviors, most QML objects use property bindings.
Property bindings are a core feature of QML that lets developers specify relationships between
different object properties. When a property's dependencies change in value, the property is
automatically updated according to the specified relationship.
Examples
Basics about property bindings
ApplicationWindow {
visible: true
width: 400
height: 640
Rectangle{
id: rect
anchors.centerIn: parent
height: 100
width: parent.width
color: "blue"
}
}
In the above example, the width of Rectangle is bound to that of it's parent. If you change the width
of the running application window, the width of rectangle also changes.
In the simple example, we simply set the width of the rectangle to that of it's parent. Let's consider
a more complicated example:
ApplicationWindow {
visible: true
width: 400
height: 640
Rectangle{
id: rect
https://riptutorial.com/ 24
anchors.centerIn: parent
height: 100
width: parent.width/2 + parent.width/3
color: "blue"
}
}
In the example, we perform arithmetic operation on the value being binded. If you resize the
running application window to maximum width, the gap between the rectangle and the application
window will be wider and vice-versa.
When using instances of QML files by directly declaring them, every property creates a binding.
This is explained in the above examples.
When the size of the mainWindow changes, the size of the created PopUp is not affected. To create a
binding you set the size of the popup like this:
https://riptutorial.com/ 25
Credits
S.
Chapters Contributors
No
Getting started with Akash Agarwal, Beriol, Community, CroCo, dangsonbk, jpnurmi,
1
qml Mailerdaimon, Massimo Callegari, Mitch, Violet Giraffe
Creating custom
3 folibis
elements in C++
4 Integration with C++ Beriol, Brad van der Laan, folibis, Violet Giraffe
https://riptutorial.com/ 26