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`). <p class="ad"> <b>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:</b><br><br> <a href="https://leafnode.nl">I'm developing an open source monitoring app called Leaf Node Monitoring, for windows, linux & android. Go check it out!</a><br><br> <a href="https://github.com/sponsors/RaymiiOrg/">Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.</a><br><br> <a href="https://www.digitalocean.com/?refcode=7435ae6b8212">You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $100 credit for 60 days. </a><br><br> </p> 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 <http://www.gnu.org/licenses/>. 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.