Analysing QtQuick apps with GammaRay or “Why is my button gone?”
This is a typical situation when you program a GUI for an application. You have just created a new control, you start your application and… no control. But now: Is it obscured? Is it misplaced? Is it completely transparent or set to ‘invisible’? Is my custom OpenGL-stuff broken or is the item actually not created for some reason? Checking all these cases manually can be a time-consuming and exhausting task.
“Come on, it’s got to be easier than this!”
In the web-development world people are used to tools like Firebug or the Chrome developer tools, which allow you to debug websites, showing you the HTML tree with CSS properties and highlighting selected elements. They cover exactly this use case.
In the Qt-world we have GammaRay, the Qt introspection tool, to make our lives easier in regard to real-time analysis of applications. Just as you can introspect the skeleton of a human with an X-ray unit, so you can introspect the skeleton of Qt applications with GammaRay. GammaRay is able to show you the internal tree of QObjects and their status and even allows you to manipulate the application’s state in real time.
One of the many handy tools GammaRay provides is a module for analysing QWidget based GUIs. You can select widgets, check their position and visibility, etc. A similar tool exists for GUIs based on QGraphicsView. The recent version 2.1 release of GammaRay completes the collection of GUI-tools with a tool for inspecting QtQuick2 applications.
Let’s check how it will help us track down all the possible causes for the absence of our button…
“Could it be that it doesn’t exist at all?”
The most basic feature of GammaRay’s Quick inspector is the tree view of all QQuickItems in the item tree. You will discover it on the left side of the UI. Apart from answering the most basic question “Which items do exist?” and providing navigation, it will already provide you with some additional information:
- “which items are actually visible?“ (items with visible == false will be greyed out)
- “which item has focus?” (More on that later on)
- it will warn you if it suspects something is wrong with the items (e.g. Items that are outside the visible area, but still have visible == true are either misplaced or unnecessarily slow down rendering)
- it will discreetly highlight items that receive events (you will discover a subtle purple text color, fading back to black after you e.g. click on a mouse area)
“Could it have set visible == false or opacity == 0?”
If you have used GammaRay before, this one will be familar to you. Right to the item-tree there is a detail-view, providing information about the state of the item. Just as in the object inspector, you can:
- see all the properties with their values (hint: since 2.1 you can right-click QObject* properties to get a detailed view in the appropriate tool) and change them inline
- inspect signal-slot connections and log signal-emissions
- directly invoke slots and Q_INVOKABLE methods
- check Qt-known enums and
- class-info data
Any changes you make to properties in GammaRay will directly influence the original app, so you can easily turn a green rectangle red or set an item invisible to check what’s below it.
“Might it be size ‘zero’ or misplaced?”
The Quick inspector tool has a live-preview of the QtQuick scene inside the GammaRay window. Here you can:
- zoom in to a specific area and measure distances in the scene in order to achieve pixel-perfect UIs.
- send mouse and key events to the app, so you can control it remotely. This especially comes in handy, if you need to debug a device, that does not lie directly besides you.
- activate some cool hidden debugging features, QtQuick ships by default (more on that later on).
- easily check the geometry and positioning of an item.
The last-mentioned feature is what you need to answer our question if the geometry is right. If you select an item in the item-tree above, the preview will be annotated with information about geometry and layouting of that selected item. The item’s bounding rect is highlighted in red. Anchor-layouts, including margins and offsets or x/y offset, are displayed graphically, depending on whatever is used for layouting. Transformed items will additionally have the original size and position displayed as well as the transformation origin.
“Is it possibly obscured?”
GammaRay has quite some helpful tools for debugging QtQuick applications. But it is not the only one. QtQuick itself already provides some very cool stuff for debugging, though most of it is quite hidden.
Since Qt 5.3, one cool feature the QtQuick scenegraph has, is visualizations for various things directly inside the application using the environment variable QSG_VISUALIZE set to either “clip”, “overdraw”, “batches” or “changes”. One of them (overdraw) helps to spot items that are completely or partly obscured by other items.
It does not make sense for GammaRay to reinvent the wheel here and recreate the same features, but GammaRay can make them available and even enhance them by making them triggerable in real-time. The toolbar in the top-left corner of the preview contains icons to en- and disable the visualize$STH render modes dynamically. See the link for more information about this scenegraph-feature.
“Or is the scenegraph or OpenGL stuff of my custom item broken?”
When writing complex, fancy QtQuick applications, you might at some time come to the point, where you need a custom item type, with its own geometry, textures and shaders. QtQuick provides tremendous flexibility here, while still hiding it behind a very nice API, in case you don’t need it. Everything you can do with OpenGL is possible.
With all the possibilities of OpenGL comes all possibilities of mistakes. In fact on the OpenGL side almost the same questions reappear: Does the scenegraph node exist? Are the properties correctly set? Is the geometry correct? What do the shaders do?
While being a full OpenGL debugger is out of scope for GammaRay, (there’s apitrace and vogl for that), providing some high-level insights into the scenegraph nodes and their OpenGL properties is not. The tree view of items mentioned earlier has two tabs: “Items” and “Scene Graph”. “Items” shows the QQuickItems, as described above, “Scene Graph” shows the graph, that is generated by the QtQuick engine. Each item provides one or more scene graph nodes, that hold a transformation matrix, an opacity value, a geometry, textures and/or shaders. These nodes are then composed by the QtQuick renderer to a scene, that gets passed to the GPU for rendering.
As with items, you can use it to see if all nodes exist and check their basic properties. As soon as you select a Geometry Node, you will however discover two new tabs in the property-view:
- Geometry: This tab displays a table of the raw OpenGL vertex data and uses the vertex coordinates as wireframe. You can check the vertex-positions and check the properties they will pass to the vertex-shader.
- Shaders: This tab simply offers you the possibility to have a look at the shaders. It basically allows you to check whether the shaders are correctly set.
We already have a lot of ideas (e.g. list uploaded textures and set them in context, display in and output-values for the shaders, etc.), but this first batch of features already helps track down quite a lot of common errors.
Focus debugging – “Where does my key-press get stuck?”
Finally the GammaRay QtQuick inspector is not just all about finding missing buttons. Another common source of problems in the context of QtQuick, where tools have been missing so far, is focus. You have added a text edit, have set focus: true but when you run it, the text you enter arrives nowhere. You will want to know: “My item should have focus. Why doesn’t it have the active focus?” (hint: there’s a difference between focus and active focus) “Which item does have the active focus?” and finally “Where does my key press actually arrive?” (this is the active focus item in the first place, but if that doesn’t accept it, it will be passed on to its parent).
If you take a deeper look at the Item tree, you will find that some items have more than one small icon besides them, like a warning-icon or spotlight icons. While the warning icon states that there might be something wrong with this item (as mentioned earlier), the spotlight icons are the important bits for focus debugging. Basically the spotlight marks items, which have focus (focus == true). The turned-on spotlight icon marks the one item that has active focus (activeFocus == true) and thus actually will receive key events, while the turned-off spotlight marks items that have focus but no active-focus (like it has focus set to true but is on a hidden tab or on an inactive window and thus won’t receive events). These icons answer the first two question.
The last question is answered by another feature I mentioned in the context of the item tree view. It’s the small purple text highlighted on the items in the tree, when it receives an event. The color of the text turns to purple and fades back. This highlight is triggered on any kind of event, including mouse and key events. In this way, you can easily trace, which items receive your key-press.
Stop digging, start hacking again!