Nico Vertriest

Getting Started with QML

Published Friday September 28th, 2018
13 Comments on Getting Started with QML
Posted in Qt Quick 2.0, Qt Quick Controls

This tutorial shows how to develop a simple alarm application as an introduction to QML and Qt Quick Controls. Until 5.11 the documentation did have an example “Getting Started Programming with Qt Quick“, but that was not really written for someone who is a complete beginner in QML, nor did it use Qt Quick Controls.

The example is available in 5.12 and can be found here: Getting Started Programming with Qt Quick.

This is a simple app where the main screen is a ListView, and where most fields are filled using the Tumbler QML type. The app stores the alarms in a ListModel. The application is very similar to the alarm application usually found on an Android or IOS phone.

User Interface

The main screen shows the list of saved alarms:

mainscreen

The detail screen becomes visible when you click a particular alarm. It lets you edit or delete existing alarms. You can also select days on which the alarm needs to be repeated.

detailscreen

The dialog screen is used for adding new alarms. It pops up when you click on the “+” RoundButton on the bottom of the main screen:

addalarms

 

Entering and Saving Alarms

Most data is entered with the Tumbler QML type. Below you can see part of AlarmDialog.qml, the dialog for entering new alarms.qml.

    contentItem: RowLayout {
        RowLayout {
            id: rowTumbler
            Tumbler {
                id: hoursTumbler
                model: 24
                delegate: TumblerDelegate {
                    text: formatNumber(modelData)
                }
            }
            Tumbler {
                id: minutesTumbler
                model: 60
                delegate: TumblerDelegate {
                    text: formatNumber(modelData)
                }
            }
        }

        RowLayout {
            id: datePicker

            Layout.leftMargin: 20

            property alias dayTumbler: dayTumbler
            property alias monthTumbler: monthTumbler
            property alias yearTumbler: yearTumbler

            readonly property var days: [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

            Tumbler {
                id: dayTumbler

                function updateModel() {
                    // Populate the model with days of the month. For example: [0, ..., 30]
                    var previousIndex = dayTumbler.currentIndex
                    var array = []
                    var newDays = datePicker.days[monthTumbler.currentIndex]
                    for (var i = 1; i <= newDays; ++i)
                        array.push(i)
                    dayTumbler.model = array
                    dayTumbler.currentIndex = Math.min(newDays - 1, previousIndex)
                }

                Component.onCompleted: updateModel()

                delegate: TumblerDelegate {
                    text: formatNumber(modelData)
                }
            }
            Tumbler {
                id: monthTumbler

                onCurrentIndexChanged: dayTumbler.updateModel()

                model: 12
                delegate: TumblerDelegate {
                    text: window.locale.standaloneMonthName(modelData, Locale.ShortFormat)
                }
            }
            Tumbler {
                id: yearTumbler

                // This array is populated with the next three years. For example: [2018, 2019, 2020]
                readonly property var years: (function() {
                    var currentYear = new Date().getFullYear()
                    return [0, 1, 2].map(function(value) { return value + currentYear; })
                })()

                model: years
                delegate: TumblerDelegate {
                    text: formatNumber(modelData)
                }
            }
        }
    }

Clicking on “OK” adds the new alarm to the ListModel with id alarmModel.

    onAccepted: {
        alarmModel.append({
            "hour": hoursTumbler.currentIndex,
            "minute": minutesTumbler.currentIndex,
            "day": dayTumbler.currentIndex + 1,
            "month": monthTumbler.currentIndex + 1,
            "year": yearTumbler.years[yearTumbler.currentIndex],
            "activated": true,
            "label": "",
            "repeat": false,
            "daysToRepeat": [
                { "dayOfWeek": 0, "repeat": false },
                { "dayOfWeek": 1, "repeat": false },
                { "dayOfWeek": 2, "repeat": false },
                { "dayOfWeek": 3, "repeat": false },
                { "dayOfWeek": 4, "repeat": false },
                { "dayOfWeek": 5, "repeat": false },
                { "dayOfWeek": 6, "repeat": false }
            ],
        })
    }

Some notes…

The program handles only the user interface and the ListModel that is storing the alarms. There is no code for storing the alarms physically in JSON format or SQLite, nor for the actual triggering of the alarm with sound or a popup window. Maybe that would be a nice challenge for someone starting with QML.

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in Qt Quick 2.0, Qt Quick Controls

13 comments

Konstantine says:

Yoi didn’t provide full sources. For beginners it’s hard without.

Alessandro says:

It should be here, but the link is broken: http://doc-snapshots.qt.io/qt5-5.12/qtdoc-tutorials-gettingstartedqtquick-example.html

Nico Vertriest Nico Vertriest says:

Alessandro, thanks for the comment. I had to make the document temporarily unavailable. It is now available with the source code.

Nico Vertriest Nico Vertriest says:

Sorry about that. I have now included them.

Ravikiran says:

The Getting Started with QML is a good introduction to the subject.

Nico Vertriest Nico Vertriest says:

Thanks ๐Ÿ™‚

tom says:

does anyone else get a
qrc:/AlarmDelegate.qml:89: ReferenceError: alarmModel is not defined
when trying to delete an Alarm ?

Nico Vertriest Nico Vertriest says:

In main.qml change the following:
model: AlarmModel
Modify this to:
model: AlarmModel { id: alarmModel }

I have now corrected this in the source code.

tom says:

thanks !

Dani says:

To some extent, I can understand you’re aiming to sell QtQuick and QML as the future of Qt. But my stomach cannot really cope with Javascript (and I’m a web dev btw). The question is, I guess QtQuick and QML are entirely optional right? Can I still use all Qt features with C++? Is there something that can be done with QTQuick/QML that cannot be done with Qt C++?

Philip S says:

I’ve been using QtQuick and QML since its inception in Qt4. I don’t see the hold up with Javascript? I rarely write anything longer than a few lines of javascript (per binding) while using QML. QtQuick and QML provide bindings, which significantly improve speed in implementing UI’s. For example if you have a text label that updates from the backend, in QML you just need Text { text: someObject.text + ” my text label”}. Now the text label will update automatically, based on someObject’s text property from Q_PROPERTY system. If you were going to do the same thing in QtWidgets you have to pass the object pointer into the widget, then handle all the connections, and initialization. If the object get’s deleted you have to manage dangling pointer and null pointers. All of this equals lots of boiler plate code. On the other hand, QtQuick takes care of this all for you. Also QML forces developers to write model / view code. On a daily basics, I have to deal with QWidget code where the previous developers stored and processed data in the widgets. It’s painful to modify… QML allows me to developing custom UI quickly. In QWidgets, you end up spending significant time writing custom QPainter code. QtQuick is speedy at rendering and animations. Because of QtQtuick/QML declarative nature, it’s amazing tool for creating and maintaining UI’s. Even creating a custom rendering pipeline with a FrameGraph is easier with Qt3D and QML than writing something similar in C++. Of course, I would never use QML by itself. All my backend code is written in C++. The pair make good balance and a friendly development environment. I recommend using QML/QtQuick over QWidgets.

Alex says:

QtQuick/QML is only the frontend part of the GUI, it replaces QtWidgets. C++ still can be used for the backend.

Commenting closed.

Get started today with Qt Download now