Some time ago I wrote how you can build and run QML applications on N900, but since that I haven’t done anything related to QML, until now. I’m not the only one at the moment who is trying to study how QML works and how you can deploy it in your application. I have always learned by doing, so therefore I decided to write a small application with QML.
I like to photograph and I have missed a good Flickr client for N900, so it was a natural choice to write a small Flickr client. I call it QuickFlickr, naturally:) So here’s the sneak preview of QuickFlickr. On the video I run it on Mac, because it takes too much time to build exactly the same version of Qt and Declarative module that I’m running on my laptop.
The application is far from ready and it lacks of proper graphics and bunch of functionality like uploading local images to the Flickr, but I will work on this app in order to learn more QML. I also managed to improve the performance quite much after I shot this screencast. I’ll add another video where you can see the performance improvement.
QuickFlickr – the Design
One of the design issues that I wanted to try, was to implement actual Flickr API usage in C++ using QtFlickr library and to provide all the content from C++ side to the UI / QML side. The QML side only visualizes the data that comes from C++ side. I didn’t want to implement too much logic in QML side.
Working with QML
I spend most of the time to make Flickr API to work in C++ side and then the rest of the time I spend for doing QML. I was really amazed how fast I could create the basic functionality there like displaying the content of a model in a Flickable ListView only with a few lines of code: a ListView item and delegate item. In the C++ side, I created the UI by using QDeclarativeView which I used for loading the main QML component which constructs the UI. I also used it for accessing the QDeclarativeEngine and to the root context.
I have implemented almost identical functionality with Qt/C++ and QGraphicsView and it really took ages to get it working. With QML it took only few hours to get really neat looking stuff. Another positive thing was that because you don’t need to re-compile the code after the smallest change, you can see the result very fast.
As I stated it didn’t take too much time to implement the basic functionality in QML side, but fine tuning all the details took pretty much time. I also spend couple hours to solve some issues that I ran into every time after updating the Qt version, but it is acceptable at this point because the Declarative module is under development.
If you don’t know what Anchored layout is, it’s worth to check it’s documentation from here. At first I thought that how I can do most of my layouting using it, but after a while, I noticed that it’s pretty easy way to implement quite complex layout. Yes, there also are Grid, Row and Column layouts, so don’t be worry about that.
You can also easily define AnchorAnimation for AnchorLayout in a Transition between states (AnchorChanges). For example in a QuickFlickr’s Fullscreen View’s “Details” state, the Image is moved from the middle to the left and scaled down little bit.
The next picture demonstrates how I used AnchoredLayout in a FullScreenDelegate object. That object contains two states: one state for showing only a fullscreen image and the other state for showing the details.
In the image above the FullScreenDelegate displays only an image inside a black rectangle. All the other items in a delegate are set to invisible with 0 opacity.
In the second state, the FullScreenDelegate displays more information about the image such as title, tags, views, description and views. The image is scaled down little bit to make more room for other items. I’m not sure how good design this is for a delegate, but it “Works for Me”:)
In my opinion Anchored Layout is a powerful layout and you can create complex layouts even though it looks quite simple at first glance.
Problems with Layouts
As you can see from the video, I used Grid layout in the main page. I tried to use Grid’s “add” and “move” transitions e.g. when the application starts, those menu items would “fly” there and they did, but they somehow moved the whole Grid to the wrong position. I guess, I need to file a bug from this.
Data Models, Delegates and Views
If you’re familiar with Qt you have probably ran into data models. With QML you can use data models to make e.g. a ListView, a GridView or a PathView to display some content. This works pretty much in a same way as using them with Qt/C++. As you can see from the video, the UI has been built by using only a Grid (main page) and a ListView (contact uploads and photostream).
In QuickFlickr application, I decided to provide data e.g. contact uploads or photostream of contacts using data models. In C++ side I used QtFlickr API to get some content from Flickr. I created a one class called FlickrItem which I used for encapsulation of a single item from a Flickr. I created a QList<FlickrItem*> and that list (data model) was passed to the QML side for a ListView. With this approach, I didn’t use the full blown QAbstractItemModel which is also supported by QML… I was bit lazy in that sense;P
Having a data model and a view is not enough to get model content to visualized. (Images above) You still need to create a delegate. Delegate is used for “drawing” the content of the single FlickrItem. This is where QML is very handy. Delegate can access the data of C++ object (FlickrItem) via Qt’s property system. So for example FlickrItem introduces bunch of properties like the url of the image: Q_PROPERTY(QUrl url READ url WRITE setUrl).
From your QML delegate you can “ask/call” the property directly to get the actual data out from your object. Sounds easy and it really is.
Problems with Data Models and Delegate
Even though it was really easy and fast to make C++ data model, pass it to the QML/ListView and visualize data with delegate, found couple of problems during my experiment.
- I wanted to call a method of a FlickrItem instance, which triggers e.g. a signal in C++ side and I couldn’t make it to happen. I tried to use Q_INVOKABLE but for some reason, I was only able to call these Q_PROPERTY methods. So defining a Q_INVOKABLE void foo() in FLickrItem didn’t work for my delegate.
- Sorting of the ListView’s content is not very handy at least if using QList<FlickerItem*> approach. I’m not sure would it be possible somehow if I would have used QSortFilterProxyModel and QAbstractItemModel instead of QList. The only way how I could order the content was to order the QList before passing it to the ListView.
I used iMac and MacBook Pro for development so the performance shouldn’t be an issue there. Actually after updating Qt version at some point, the performance improved quite a lot. It is also possible to improve the panning by setting cacheBuffer large enough, but this will of course increase the memory usages.
Actually what you see on the video, is not running as well it could. After I shot the video I managed to improve the performance quite a lot by setting QGLWidget to the viewport for the QDeclarativeView. On the video I ran it by using “-graphicssystem opengl” switch, which doesn’t seem to work as well as it could.
Addition: Here’s the second video of the QuickFlickr where I manage to improve the performance. Too bad that the screentoaster that I used for getting the screencast, doesn’t show it running as fast as it was runnign while recording. I guess, I need to find some proper software for capturing screen (not for stills:).
As C++ programmer, I think the biggest challenge for me was to change the way of thinking. In C++ for example the scopes of the variables are pretty tight. Of course this depends on the way how you program, but in QML it was hard to get used of it that you can access members or properties of a QML component from another component.
This chapter is called “Declarative Thinking” and why I wanted to raise this change of thinking is because of interfaces get more important when implementing QML based application. With this I mean, that in a real life, I believe that most of the QML applications are split in two: the C++ and UI/QML side.
To design application properly it requires more from C++ developers to introduce better interfaces for QML developer. I’m not saying this is bad, actually it is much better because this way it forces C++ developers to do their job better.
Graphics View, Qt Quick and Next Generation Widgets
QML is based on GraphicsView i.e. each QML Item is an instance QDeclarativeItem which inherits QGraphicsObject. If you use QDeclarativeView in your application for instantiating your QML UI it actually creates QGraphicsView and QGraphicsScene and hides all the bulk stuff like creating QdeclarativeComponent and so on.
I must humbly bow all the Trolls who have make this possible because it’s really amazing how well the Declarative module seems to integrate to the existing Qt code base.
One lack of QML and of GraphicsView is the lack of widgets. If you want to build your own application on top of QML or GraphicsView, then you will need to create all the widgets (buttons) yourself. QML introduce Item for TextEdit and in QgraphicsView side there QgraphicsTextItem. I believe that one reason for the fact that there is no “widgets” for QML and for QgraphicsView is that when the next generation widgets are ready, then the widgets can be usable for both QML and GraphicsView.
Some time ago I had a small discussion with one of the Trolls who told me that the plan for NGW is that they will separate the current “Control” part for the existing QWidgets. The control part is used for drawing the actual primitives of the QWidgets via Qt’s style system. When the Contol part is separated, then it can be used from QGraphicsView side also. After this it “only” requires that there is a QGraphicsWidget/Object based widget, which uses the same controller than the corresponding QWidget based widget. This way the both widgets will get same appearance based on the platform style. The drawing only happens in a different place and in GraphicsView’s case it happens in GraphicsScene.
This was just my guess, why there aren’t any widgets in QML side at the moment. Interesting to see where all this will go.
I can consider myself as a C++ developer and therefore it wasn’t so straightforward to get into a QML. I manage to build pretty neat QML based UI for QuickFlickr less than 10 hours starting it from scratch. During the development, I reported a few bugs, which were fixed really fast. When I ran into some problems, Trolls were very helpful in QML irc channel #qt-qml @freenode.
If you’re interested in about QML and how it works, just crab the source code, build it and start QMLing. I believe that the Trolls who are developing QML are more than satisfied if they will get more feedback and users for QML. It’s still few months left before they will release Qt 4.7 so let’s help them to do it as good as it can.
Thanks for reading my blog.