Scythe Studio website employs cookies to improve your user experience (Read more)

How to write clean QML code in 2022?

Qt Qml development
2022-03-16
11 minutes
How to write clean QML code in 2022?

There is no argue that QML is an amazing technology to develop an outstanding user interface matching today’s trends. The QML language has beautiful and easy to learn syntax, but the code doesn’t structure itself that. By its nature, it can easily get messy. Therefore, you need to learn how to write clean QML code in order to keep your Qt software project easily maintainable. Ergo, to make savings on money and time.

What makes QML code clean?

Let’s start by answering the question what makes QML code clean? Can the code be actually dirty? Well, yes. There are a lot of things you can do wrongly without realizing it.

QML code formatting

The code style is the way code is formatted. It is how your code looks. I find this definition pretty plain and simple. It’s true that it doesn’t affect the application’s execution in anyway, but it significantly affects the readability of your code. So, it affects the application’s maintainability and therefore time future developers would need to make changes.

Code formatting is about indentation, use of white spaces and new lines, code grouping and organization. Many of those things are personal and there is no point in arguing about small things like where the opening bracket should be. The goal is to have consistent code formatting across the project. I have seen software developers who couldn’t be persistent in their own code, so it’s even more difficult when more people work on the same codebase. That’s why you should try automating code formatting.

Tip #1 for better QML code formatting

QML code has a tendency to have many nesting levels and it quickly spreads too much to the right. Therefore, my first tip would be to decrease the indent size to 2 spaces to limit this effect.

In order to do that, enter Qt Creator Options and navigate to Qt Quick settings. You should find a tab related to the code style. You cannot edit the default code style, so click on the Copy button in order to create your own style.

 

qml clean code

After giving your style a name click on the Edit button in order to modify the details of newly created style. I wish there were more options to adjust, but at least indentation settings can be changed here. You should see that both Tab size and Indent size equals 4. Decrease them to 2 and you are done. The change should be reflected in the code editor and by tools like Reformat file tool.

 

qml clean code

Tip #2 for better Qml code formatting

Another tip would be to use QML/JS Reformat file tool. How does it work? It takes your code and reformat it just to look nicer. Let’s have a look at the component below.

 

import QtQuick 2.0

Item
{
    id: root
    
    width:30;height:50;
    
    Text {
        id: textItem
        font.pixelSize: 48; wrapMode: Text.WordWrap
        lineHeight: 0.75
        Behavior on color { ColorAnimation { duration: 120; easing.type: Easing.OutElastic} }
        states: [State {
              name: "pressed"
                when: mouse.pressed
                PropertyChanges {
                  target:  textItem
                    color :Qt.lighter(root.color)
                }}
        ]
    }

    MouseArea {
        id: mouse
        anchors.fill: parent
        onClicked: {
            // ...
        }
    }

    function foo()
    {
        // ...
    }}

It’s definitely not the most beautiful QML code that you have seen. There are several issues including indentations that are different from each other, wrong braces positions, spaces that are sometimes missing and sometimes redundant. To fix it quickly and easily, navigate to the Tools option from Qt Creator’s top bar menu and then find Reformat file under QML/JS group. Running the tool can save a lot of your time.

 

import QtQuick 2.0

Item {
  id: root

  width: 30
  height: 50

  Text {
    id: textItem
    font.pixelSize: 48
    wrapMode: Text.WordWrap
    lineHeight: 0.75
    Behavior on color {
      ColorAnimation {
        duration: 120
        easing.type: Easing.OutElastic
      }
    }
    states: [
      State {
        name: "pressed"
        when: mouse.pressed
        PropertyChanges {
          target: textItem
          color: Qt.lighter(root.color)
        }
      }
    ]
  }

  MouseArea {
    id: mouse
    anchors.fill: parent
    onClicked: {
      // ...
    }
  }

 function foo() {// ...
  }
}

If you’re committed enough to give up Qt Creator some control over your QML code formatting, then try setting up Reformat file tool to be run automatically on file save.

 

qml clean code

QML coding conventions

Coding conventions go beyond the remit of formatting. The QML code can be formatted nicely and look okay from the code style perspective, but it may need polishing anyway. In Scythe Studio we are pretty restrictive about our coding conventions that slightly differ from official QML coding conventions, but they also add a lot of other concepts. However, these official conventions are good for you to start with, so following them is suggested.

Below you will find a few of the conventions that we follow in Scythe Studio company in order to provide high quality Qt Qml software development services and have clean QML code. We enforce following conventions even on job candidates while working on their technical assignments.

1. Root item id

In order to improve readability and traceability, setting an id of top-level item in a file to root is suggested. Then, in every single file you know that the reference to root is about top-level item.

 

import QtQuick 2.0

Item {
  id: root
}

2. QML string translations

If the string is visible to the user always wrap it in qsTr() function. Also instead of using end translation as strings displayed by default use THIS_NOTATION. For example instead of writing text: qsTr(„This is displayed”) use text: qsTr(„THIS_DISPLAYED”). Thanks to this approach if any string is missing a translation we instantly can see that in UI.

3. Have a private object

Encapsulation and proper scoping should matter when you code in QML. Just like in C++ you do not want all members of your class to be public, so the same should apply to QML code. Not all properties and functions should be visible from the outside. There is often a need for helping properties and functions, but they have no value or can even cause some unexpected harm when used from outside. Therefore wrapping them into an internal QtObject is suggested.

 

QtObject {
  id: _ // or id: internal
    
  readonly property real timeout: 1000
  property bool isExpanded: false

function addDestination() {
    // ...
  }
}

4. Order of various attributes

Official QML conventions cover order of attributes, but we just define it a bit differently and in more details. It simply pays off in big projects.

 

import QtQuick 2.15
import QtQuick.Controls 2.15 // Qt modules first
import com.scythestudio.ownmodule 1.0 // then own modules
import "./controls/" // then local directories

// A hypothetical custom button item.
Item {
  id: root

  /// The text to be placed on the button
  property string title: "title"                           // properties declaration
  /// The button's background color
  property alias color: button.color

  signal buttonClicked()                                   // signal declaration

  Button {                                                // child items
    id: button

    width: parent.width                                   // properties derived from Item
    height: parent.height

    icon.color: "black"                                   // Button's own properties

    onClicked: {
      root.buttonClicked()
 }
  }

  states: State {                                         // states
    name: "selected"
    PropertyChanges { target: button; icon.color: "red" }
  }

  transitions: Transition {                               // transitions
    from: ""
    to: "selected"
    ColorAnimation { target: button; duration: 200 }
  }

  PropertyAnimation {                                     // special items
    id: closeDelayAnimation
    // ...
  }

  Timer {                                                 // special items

  }

  Connections {                                           // special items
    target: someCppController

    function onProcessFailed() {
      // ...
    }
  }

  QtObject {                                               // private item
    id: _

    readonly property real timeout: 1000
    property bool isExpanded: false

    function addDestination() {
        // ...
    }
  }

  onWidthChanged: {                                       // slots

  }

  function close() {                                      // public functions
    isExpanded = false
    closeDelayAnimation.start()
  }
}

 

From the code snippet above you can deduce a lot of rules, but let’s highlight three:

  • Functions definitions are preferred to be on the bottom of the file in order to see component’s children first and quicker understand how the item is built;
  • States and transitions tend to grow fast, so that’s why they should be placed below children though they are also properties;
  • Component’s public API should be documented;

Good QML practices

In the documentation of the Qt framework, you can find a list of best practices for QML and Qt Quick. I find all of them quite useful and some of them principle to have a clean QML code. Probably the most crucial practice described on that page is a rule to separate UI from logic. When you code using QML, you may be tempted to use QML and JavaScript for many things including application’s logic and network communication.

Try then to move such things to C++ as then you have a clear separation of the frontend written in QML and let’s say the backend written in C++. Therefore, your application’s architecture offers more scalability. One of the things that should almost always be written in C++ are data models. You can go with QML models only if your list is static. Otherwise, you will finally either lose your time on trying to perform advanced operations using QML models or on rewriting them to C++ models.

In Scythe Studio we conduct online and offline workshops dedicated to various aspects of Qt software development. One of the workshop topics is „How to design an architecture for your Qt Quick application?”. Contact us to learn more about our workshops offer.

Tip for easier handling QML issues

Another good practice is to use qmllint tool that would help you easier spot the issues in your Qml code. It’s a pretty useful tool warning about many issues including unused imports and unqualified access to properties. The Qt company is currently working on a better integration of this tool with Qt Creator IDE.

Why is it important to write clean QML code?

At this point you should know what clean code means and what you can do to ensure that the code you write follows these rules. So now let’s answer the question why is it so important to write clean QML code? It’s one of the factors that makes your code high quality. When you have a set of conventions and rules to follow, it’s easier to spot errors and therefore you immediately start to make time savings. Moreover, as clean code concepts include good practices, the developers who follow these directives write code according to the art. It doesn’t require then that much effort during the reviewing process.

When you code there are plenty of tiny decisions to make and after looking at the very same code after some time, you rather have no idea why you wrote the code in a particular way. On the other hand, when you follow clean QML code rules, you outsource those little decisions to the code. It frees up your thinking resources.

Finally, of course, the most important reason to write clean QML code is the fact that it significantly improves the maintainability of the project. Someone said that you write the code once, but it’s read multiple times. Therefore, you need to care about readability of your code as well as about all the good practices. Then it’s easier for you and other developers to jump into the project, understand a particular piece and make changes.

Now you may ask how strict about following clean QML code rules your team should be. Well, it all depends on the length of the project that you’re currently working on. It is also important how many people participate or will participate in the future. My point of view, it’s hard to overdo it when it comes to ensuring high quality code. Even if you prepare a small demo of which code will be public, it’s good to follow all these rules to be finally content with the results of your work. After a while, it gets into the blood and developers stop even thinking about it as an additional effort.

If you maintain a long-life project such as Qt framework, you have many reasons to be extremely restrictive about the code quality. I described my experience of contributing to Qt Charts in Qt 6.2 module in a blog post. There are a lot of conventions and rules to follow and it’s actually quite difficult at the beginning to get used to them. There are though CI/CD mechanisms that save reviewers time by, for example, looking for typos. At the beginning it was a struggle to make my code match all those requirements. Nevertheless, I know that it’s a must-have in this project and I can say that it was even enjoyable

Key takeaways and general rules

  • Maintaining a clean QML codebase is an important aspect of a healthy Qt project;
  • KISS – keep it short and simple. Not for you, but for the reader. Always choose the simpler implementation option over the more complicated one;
  • Document public interfaces (API) of created items;
  • Do not add comments describing how something is achieved. If the reader can’t deduce that from your code, then code needs refactoring. Comment on not obvious solutions that may look surprisingly;
  • Do not re-invent the wheel;
  • Adapt the code to the existing codebase. If you have improvement ideas, first discuss them with other developers;
  • Follow the coding conventions and good QML practices;
Scythe-Studio - Chief Executive Officer

Łukasz Kosiński Chief Executive Officer

Need Qt QML development services?

service partner

Let's face it? It is a challenge to get top Qt QML developers on board. Help yourself and start the collaboration with Scythe Studio - real experts in Qt C++ framework.

Discover our capabilities

Latest posts

What is cross-platform development? main image

What is cross-platform development?

Cross-platform development is a popular solution for creating applications compatible with different operating systems, devices, or platforms. Compared to the native approach, cross-platform development in the most cases gains valuable time. You do not have to focus on each platform separately, which very often requires more financial and physical resources. It is worth remembering that the greater availability of your application allows you to reach a wider group of customers. In turn, thanks to popularity, you can achieve potentially better benefits. In this post, we’ll break everything down and analyze the topic of cross-platform development so that you can familiarize yourself with it without a lot of effort.

Scythe-Studio - Junior Lead Generation Specialist

Ewa Orzeszyna Junior Lead Generation Specialist

How to integrate C++ and QML? Expose object and register C++ class to QML main image

How to integrate C++ and QML? Expose object and register C++ class to QML

This tutorial about how to expose object and register C++ class to Qml is the first post in the new post series on Scythe Studio blog. The series is going to be entitled „How to integrate Qml and C++”. With the new Qt 6 version it’s not that clear how to properly and easily implement this crucial mechanism in Qt software development. Especially as many people currently move to CMake from qmake. Therefore, we thought that it would be a nice opportunity to explain various ways of Qml and C++ integration in details.
Future posts will cover mechanisms like models and plugins, but for now let’s focus on the basics and let’s explain how to access C++ object from Qml and how to register C++ class to QML.

Scythe-Studio - Chief Executive Officer

Łukasz Kosiński Chief Executive Officer

Fixed-price vs Time and materials − what is best for your project? main image

Fixed-price vs Time and materials − what is best for your project?

Outsourcing has become a widely popular model for running business in the modern world and there is no surprise. Companies specializing in one field do not need to allocate finances, employ people and plan their job in a field they have no experience and knowledge at ― they may take advantage of outsourcing companies. These can be services of any kind ― IT, design, finances and other. However, when it comes to selecting a model for the contract and project’s realization, there might be an issue what to choose for your project. Mainly, there are two different approaches ― Fixed-price Model and Time and Materials Model. In this article we will discuss both models and identify their pros and cons in order to select the approach which suits your project best.

Scythe-Studio - Blog Redactors

Scythe Studio Blog Redactors