Satori-ProjectHave you ever heard the phrase “If you have one watch, you always know what time it is. If you have two watches, you are never really sure!”
While choices are often a benefit, things can certainly be simpler if there is only one option available. This brings me to the current situation with Nokia’s Qt framework. Until recently, you had all of the standard UI elements (buttons, images, labels, scrollbars, etc) available as QWidgets that you placed in layouts to arrange in your GUI. The framework made it pretty easy (especially using PyQt or PySide to develop without needing to compile anything) to develop “standard” UI’s quickly and provided all of the hover, click/double-click, drag-and-drop functionality you needed.
Ah, the good old days. A simpler time….
With Qt 4.7 recently released, you have not one, not two, not even three different ways to develop UI’s. Now you have four ways. Going back to the watch analogy, if one watch is broken you don’t have an issue. But what if they both work? Do you trust the new one, simply because it is newer? Trust the old one, as maybe you are used to it, and it is reliable?
That’s the situation I found myself in with Qt’s graphics technology, and hopefully my experience will help others.
Now this is all a guess, but I think the evolution of these new technologies started with wanting to make a game with Qt. “Standard” UI’s have a specific purpose – something you want the user to be able to select or manipulate. You create a window and put all of the relevant “stuff” on it. And QWidgets are great for that.
With a game, though, you don’t have a fixed set of stuff. More likely you have a world you are able to explore. And that means your elements move and change. And QWidgets are not great for having lots and lots of elements that may or may not be visible and can have very different interactions. To solve this type of problem, Qt started using QGraphicsView and QGraphicsScene, which (I think) led to the three other UI techniques. The Scene is the world, which is what you put you graphical elements on. The View defines that part of the scene that is shown to the user. This separation allows for things like Qt’s impressive 40000 chips demo. What’s cool about the demo? Two things in particular. First, having different Views of the same Scene is something that can’t easily be done with QWidgets. Second, you don’t have to paint elements that aren’t part of a view and you can simplify the paint routine if an element is very small in the view. This can save a lot of processing, which makes it easier to scale to more elements or making the elements more complex by, for instance, adding animation. With QWidgets, elements are placed in layouts, which ties the size and shape of one element to the size and shape of those around it. In a Scene, the elements are placed independently, which makes animation much easier to manage.
So what I would call the 2nd UI technology uses the QGraphicsView/QGraphicsScene/QGraphicsItem techniques, which I will call the “QGraphicsItem stack”. The building block of the UI is the GraphicsItem, and the more specifically the QGraphicsTextItem, QGraphicsPixmapItem and the QGraphicsPathItem. Using or deriving from these Items allows you to draw whatever you need in your UI.
Seems like the end of the story, right? Except I aleady mentioned there were four Qt techniques, and we’ve only seen two.
The story continues because people like animations. On the one hand, you have QWidgets that are easy to arrange in the UI but difficult to animate, and on the other hand you have the QGraphicsItem stack which is easy to animate but hard to arrange (or layout, in Qt terms).
So the next iteration is something called the QGraphicsWidget. This is a new type, which inherits from both QGraphicsItem (allowing it to work in Scenes/Views) and also QGraphicsLayoutItem. QGraphicsLayoutItem (which is a very badly named IMHO) is a type that allows Qt to automatically arrange elements in a Scene using Scene/View versions of layouts. My problem is that QGraphicsLayoutItem sounds like it is part of the “QGraphicsItem stack”, but it isn’t. The tools you use in the QGraphicsItem stack, TextItem/PixmapItem/PathItem don’t inherit from QGraphicsLayoutItem. So you can’t use them in a layout in a QGraphicsWidget. At least not easily. Maybe you are here because you want to use QGraphicsItem in a layout, and you are hoping I explain some (not easy) trick. Sorry, not gonna happen. I tried, but there isn’t a lot of documentation available and I gave up. The problem has to do with object sizes. To layout items, QWidgets provide minimumSize/preferredSize/maximumSize properties/methods, as well as resizing preferences that are essential for Qt to handle the arranging. QGraphicsItems don’t provide these, instead they provide a boundingBox. I was unable to get these two (related) ways of handling an elements size to “play nice”. Instead of using QGraphicsItems in a QGraphicsWidget, Qt provided the QGraphicsProxyWidget which allows you to put regular QWidgets in a scene and treat them like QGraphicsItems. Ummm, ok.
So here you have the third method, what I will call the “QGraphicsWidget stack”, which is a combination of QWidgets and Scene/View, with the QWidgets wrapped in proxies. I guess this is useful if what you need is a “standard" UI + animation, using the existing QWidgets. But given the lack of documentation/examples/help, I decided not to try to make custom widgets as it isn’t clear which methods should be overridden between the QWidget methods, the QGraphicsItem methods and the QGraphicsLayoutItem methods. I think it would be best if Qt would provide QGraphicsWidget implementations of the QGraphicsItem types (Text/Pixmap/Path), but I doubt that will happen given the emphasis on the 4th method, Qt Quick/QML.
I guess the easiest way to describe QML is as a markup language (like XML or HTML) that uses a text file to describe the UI. On the downside you need to learn a new language, although it is a simplified markup language. The upside is that you can modify the UI by changing a single text file, you don’t have to recompile any source code. As I mentioned earlier, I’m using Python and the PyQt/PySide Qt bindings, and since Python is interpreted instead of compiled, I wasn’t sure I’d see much benefit from QML over describing the UI in Python. But the fact is, I like QML.
One thing that surprised me about QML is that it isn’t just a new way to create Qt objects. That is, I initially assumed that you had a library of visual objects, and whatever you could create in QML could be created in C++ (or Python in my case). With Qt 4.7, this isn’t the case. For example, a PathView QML element allows you to make an animated/flickable UI with very little code. As far as I can tell, there is no simple way to create this type of UI outside of QML. It readily supports model/view design, with the model defined in code and the view defined in QML, which I found made it easy to use my existing QAbstractItemModels, but “theme” the model in QML.
Even though Python is an interpreted language, and changes can be made by updating text files, there is a lot of appeal to allowing UI changes to be made without modifying “code”.
What time is it?
So, after trying these different techniques, what would I recommend? That depends on what you are trying to do.
Certainly there are a lot of times when you want a standard UI and animations aren’t necessary. QWidgets work great in this case.
If you are making something like a game, where the Scene/View paradigm is appropriate, I would use QGraphicsItems. You can take advantage of collidingItems() etc, to support interaction that would otherwise be difficult. QML may be appropriate at some point, but Qt Quick’s emphasis seems to be small UI’s, appropriate for smartphones and other mobile devices. I haven’t really tried, but I have the impression that trying to provide multiple views and scrolling like the 40000 chips demo would be too complicated for QML.
For animated UI’s, I would probably recommend QML. Since it is so new, it can be hard to find answers to some questions, but that will change over time. The language itself is concise and intuitive to use once you get started.
As for the QGraphicsWidget stack, I’m not sure where the value is. The only time I would recommend using it is if you are fine with the standard QWidgets and just want to add some simple animation. I can see it as a stepping stone to QML, but I’m not sure it stands on its own.