This is a text-only version of the following page on https://raymii.org:
---
Title : Rectangle{} debugging in QML, just like printf(), but for QT
Author : Remy van Elst
Date : 08-09-2021
URL : https://raymii.org/s/articles/Rectangle_debugging_in_QML_just_like_printf.html
Format : Markdown/HTML
---
![Rectangle{} debugging][7]
> Rectangle{} debugging on QML anchors
Recently I've been using a debugging technique in QT/QML that I've decided
to name `Rectangle{}` debugging, in the same vein as `printf()` debugging.
QML is a markup language (part of the QT framework) like HTML/CSS, with
inline JavaScript that can interact with the C++ code of your (QT) application.
QML has the [concept of][2] `anchors` for relative positioning of elements. Overall,
`anchors` work quite well, but can get complex when inheritance and complicated
layouts come into play. The `Rectangle{}` style of debugging places a semi-transparent
rectangle with a border around your element so you can visualize the positioning
and see what effect your changes have. This article shows an example where I
recently applied this style of debugging at work in our coffee machine user interface,
including some tips to do actual `printf()` style debugging (but with `Console.log`).
Recently I removed all Google Ads from this site due to their invasive tracking, as well as Google Analytics. Please, if you found this content useful, consider a small donation using any of the options below:
I'm developing an open source monitoring app called Leaf Node Monitoring, for windows, linux & android. Go check it out!
Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.
You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $200 credit for 60 days. Spend $25 after your credit expires and I'll get $25!
I've written about [QT / QML][4] before, that article went into signalling
and slots, a method to communicate between C++ and QML.
The [Qt Quick anchoring system][2] allows you to define relationships between the
anchor lines of different items. For example, you can write:
Rectangle { id: rect1; ... }
Rectangle { id: rect2; anchors.left: rect1.right; ... }
In this case, the left edge of `rect2` is bound to the right edge of `rect1`,
producing the following:
![qml doc example][3]
As said, this gets complex quickly, especially when anchors / positions depend on
dynamic variables that come in via signals from the C++ side. QT Design Studio
is also not usable in our projects due to platform specific limitations.
What is `printf()` debugging? It's a technique [named after][1] the ubiquitous
C function. Used to describe debugging work done by inserting commands that
output more or less carefully chosen status information at key points in the
program flow, observing that information and deducing what's wrong based on
that information.
I prefer a dedicated debugger, but it has to be good and integrated in my IDE. CLion
has this, Visual Studio has a reasonable one and QT Creator's QML debugger is just bad.
For visual elements like in QML, it's harder to debug positioning and relative
stuff. Next to that, QT Creator has a QML debugger, but that is horrible to use.
Unresponsive, missing breakpoints, all kinds of other weird stuff that just works
terrible. Using this rectangle trick makes elements, boundaries and changes very
visible. To center an object, do you use `anchors.centerIn: parent` or
`anchors.horizontalCenter: parent.horizontalCenter`? With a big rectangle
around your change, it is way more visible what a change does.
### Rectangle{} debugging
Recently I had to implement the [touchless coffee feature][8] for one of our
machine user interfaces, that uses QT. The QML control already existed, but
it had to be placed on a few screen, conditionally replacing another element
depending on a setting. The first attempt to place the control in that
other element resulted in a small, non-centered element. Below is a picture
showing the first attempt on the left and the final result on the right:
![qml layout coffee machine][5]
> QML User Interface, before (wrong) on the left, after (correct) on the right
The blurriness in the screenshots is due to the fact that I resized them to
fit better on the site, on the machine they're super crisp.
The element that was conditionally replaced, was resized and centered, the QML
syntax was copied over and it resulted in something unexpected. The first
thing I did was put a rectangle around the container, to visualize what was
going on:
Rectangle {
anchors.fill: parent
color: "#ffffff"
visible: true
opacity: 0.8
border.color: "#ff0000"
//insert your objects here
}
It looks like this:
![rectangle 1][9]
As you can see, the new qr image is not exactly on the top-leftmost corner, so
inside the QR control there is some positioning going on. Let's put another
`Rectangle` in the QR code control to see what that is doing. This time the
background color is light orange, to distinct it from the outer container:
![rectangle 2][10]
Inside the QR control the size is also not as I would expect, the centering is
correct. Remember, that specific control is already used on other UI's,
working correctly. Let's fiddle around with the `Image.Fillmode`, `Pad` or
`PreserveAspectFit` should [do the trick][15], as well as some `anchors.fill:
parent` sprinkled here and there:
![rectangle too big][11]
Almost there, as you can see, the `Code: ` text is now outside of both
controls. That has an `anchor.top: qrimage.bottom`, which is correct, but if
this control would be cropped, the text would not be visible. If I had not
used this `Rectangle{}` debugging method, I would not have noticed that,
which might cause bugs in the future.
Let's test with `Image.width: ### * 0.85`:
![rectangle fits][12]
Better, but when the control is larger, still not correct, too much space at
the bottom. Fixing that is outside of this article's scope. Continue on with
centering the control. That was a case of the correct combination of
`anchors.fill: parent` and `anchors.horizontalCenter:
parent.horizontalCenter` in a few controls. I'll spare you the details, after
a few minutes I found the correct combo:
![rectangle center][13]
The only thing left now is to remove the rectangles (or, even more evil, make
them transparent) and finish up the feature.
Without the rectangle debugging technique, I would probably not have spotted the
text being outside of the image. Or there would be discussion over if a control
is in the exact center. Making it visual and visible is so much more helpful
than staring at a debugger in this case.
If you're wondering, this is how the webpage looks after you've scanned the QR code:
![touchless coffee][14]
This specific QR code never worked since it was only active in a development
environment, but you might be wondering what would happen if you scanned the
code. It gives you a webpage with all the machines consumptions, choose one,
customize the drink and press Order. Machine starts producing it, all without
the user having to touch the screen. Uses MQTT on the backend, less than 7 MB
a month in data usage, super responsive, really cool to develop. But that is
a story for another day.
### Console.log QML debugging
QML mixes markup language with inline JavaScript, which in my case can be helpful
when debugging. For example, the visibility of an element can be determined by
QML properties or via C++ [signals and slots][4]. By replacing the `visible: varName`
with a JavaScript function call, we can log the value to the console. By doing
that, I can exclude that boolean value if an element is invisible, but should be
visible. It helps to figure out if the styling (z-index for example) is the issue
or the actual value returned.
Here is an example QML file:
Item {
function logAndReturnValue(varToLog)
{
console.log("value: " + varToLog);
return varToLog;
}
property bool varName: false;
Text {
visible: logAndReturnValue(varName)
text: "Example Text"
}
}
This simple example function takes a variable, logs it to the console and returns the result.
The `Text` element has the line `visible:`, which is the `boolean` value true or false, or
another variable containing a boolean or a function returning a boolean. By using signals
you can set this via C++ code, see my [other example][4] article for how that works.
Effectively you could just write `visible: varName`, but with this logging method, you
get it printed as well.
Next to using this method, you can also hook into the `Component.onCompleted` signal handler,
that is emitted after an object has been instantiated:
Text {
Component.onCompleted: console.log("Text onCompleted.")
text: "Example Text"
}
In my experience, the QML debugger is a hassle to work with, not even remotely as
polished as CLion's GDB integration. It's also a bit weird at times, not updating
with results, not correctly stepping over, all kinds of small issues. I often prefer
this printf-style debugging in QML due to how bad QT Creator and their QML debugger is.
[1]: http://web.archive.org/web/20161010085658/http://stackoverflow.com/questions/189562/what-is-the-proper-name-for-doing-debugging-by-adding-print-statements/189570#189570
[2]: https://web.archive.org/web/20210907091818/https://doc.qt.io/qt-5/qtquick-positioning-anchors.html
[3]: /s/inc/img/qml1.png
[4]: /s/snippets/Cpp_QT_QML_Signals_and_Slots.html
[5]: /s/inc/img/qml2.png
[6]: https://web.archive.org/web/20210907115237/https://doc.qt.io/qt-5/qml-qtqml-component.html#completed-signal
[7]: /s/inc/img/qml3.png
[8]: https://web.archive.org/web/20210126222728/https://www.dejongduke.com/news/touchless-coffee-option/
[9]: /s/inc/img/qml4.png
[10]: /s/inc/img/qml5.png
[11]: /s/inc/img/qml6.png
[12]: /s/inc/img/qml7.png
[13]: /s/inc/img/qml8.png
[14]: /s/inc/img/qml9.png
[15]: https://web.archive.org/web/20210907135855/https://doc.qt.io/qt-5/qml-qtquick-image.html
---
License:
All the text on this website is free as in freedom unless stated otherwise.
This means you can use it in any way you want, you can copy it, change it
the way you like and republish it, as long as you release the (modified)
content under the same license to give others the same freedoms you've got
and place my name and a link to this site with the article as source.
This site uses Google Analytics for statistics and Google Adwords for
advertisements. You are tracked and Google knows everything about you.
Use an adblocker like ublock-origin if you don't want it.
All the code on this website is licensed under the GNU GPL v3 license
unless already licensed under a license which does not allows this form
of licensing or if another license is stated on that page / in that software:
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Just to be clear, the information on this website is for meant for educational
purposes and you use it at your own risk. I do not take responsibility if you
screw something up. Use common sense, do not 'rm -rf /' as root for example.
If you have any questions then do not hesitate to contact me.
See https://raymii.org/s/static/About.html for details.