[Development] The place of QML

Alan Alpert alan.alpert at nokia.com
Mon Apr 23 10:59:26 CEST 2012


On Mon, 23 Apr 2012 17:35:02 ext lars.knoll at nokia.com wrote:
> On 4/22/12 9:14 AM, "ext d3fault" <d3faultdotxbe at gmail.com> wrote:
>
> >...
> ...
> >To quote Lars,
> >
> >We want to make the usage of Javascript supported as well as C++ is
> >supported. We are not making it the superior way or even the only way.
> >
> >
> >...except that the javascript way currently is the superior way. If you
> >want a hardware accelerated UI (without hacking together your own...
> >defeating the purpose of using a UI toolkit), you are forced to use
> >javascript (QML).
> 
> No, you should be using QML. That doesn't imply that you have to write any
> application logic in Javascript. As I said, use it as a better .ui
> language. You can still do all your app logic in C++ if you so want.

I don't think Lars emphasized this enough, but QML is *not* JS. In fact, the JS engine is only used when you have non-trivial 
bindings. The rule of thumb is that you have to really write code that looks like JS in order to have it interpreted by V8. So if 
you use it the same way as a .ui file, the performance characteristics are almost the same too. For example:

Rectangle {
	x: 10
	y: 10
	width: 10
	height: 10
}

This is the level of functionality that UI files provided, and it didn't need JS. Well, it still doesn't. That QML code isn't 
going to run anything through V8. The QML engine is smart enough to just assign the values and not bother using a JS interpreter. 
You end up with a C++ object instantiated, and with some properties set, which is exactly what .ui files did. So if you compare 
this to a .ui file, the only difference is that it is being compiled when you load the component instead of during the compile 
phase. Oh, and it's easy enough to write by hand as well as with the visual designer.

I understand that run-time compilation is a concrete performance cost for a static UI, and we're looking into ways of storing the 
compiled output so that you can just load bytecode to initialize objects (for the same performance characteristics as a .ui file). 
But so far our performance metrics show that the compile time is minuscule for QML applications and so it's not high enough on our 
priority list for what to optimize. Patches are welcome though :) .

> When you ask for simply exposing all a C++ API to all QML items, you're
> missing a point. QML is a language that include states&transitions and a
> binding engine. The binding engine works on arbitrary expressions and
> needs some backend to evaluate these. That backend happens to be V8.
> 
> I don't see a problem with that. You're also not complaining that we have
> PCRE as a backend to implement regular expressions.
> 
> We are already exposing most of the the C++ APIs that make sense for
> application developers to use. Simply exposing the C++ interface of all
> QML elements won't buy you anything, as the most important feature of Qt
> Quick (bindings) still can't be handled that way.
> 
> There's zero value in exposing the C++ class that implements the QML
> Rectangle element. There's nothing you can really do with it anyway. If
> you need to create your own QML elements in C++ we have QQuickItem and
> QQuickPaintedItem, which form a very good and solid basis.
>
> And as others already pointed out, we need to be careful as to what we
> expose in C++. Any API we add comes at a large cost (that you probably do
> not see) in terms of maintenance and limitations to what we can change
> because of binary compatibility.

I can see the non-zero value in exposing the Rectangle element. It's pretty much equivalent to QGraphicsRectItem then. I don't 
know about you, but I didn't find QGraphicsRectItem very useful at all. In a C++ graphics scene, it wasn't worth the bother to 
compose images out of multiple QGraphicsRectItems. That approach was cumbersome and inflexible compared to implementing your own 
QGraphicsItem and just painting a rectangle in paint(). Note that with QQuickPaintedItem, you can do the exact same thing with 
scenegraph today (well, on the day Qt5 is released ;) ) just take your QPainter* and go to town. Or use QQuickItem and paint it 
using scenegraph or GL directly, to truly get the sort of hardware acceleration and speed that requires custom C++ code. (NB: 
after writing your super-fast C++ native object you can then use QML to instantiate it and set initial properties, if that appeals 
to you.)

This is one of the main reasons we aren't exposing the elements to C++. The value for providing these elements in C++, compared to 
you doing your own painting in C++, is very ill defined. It's not zero, but there is a large cost in the limitations we have when 
we make an API public. Remember that if we change it to expose the C++ API, at even the tiniest expense of the QML API, the C++ 
haters will come crawling out of the woodwork with unbridled rage. So exposing it to C++ directly provides a very large cost for 
very little gain (that I can see). We shouldn't expose it to C++ until we have a good and highly useful C++ API at minimal cost to 
the QML API, otherwise we'll not be able to release such an API until Qt 6. I don't know if I'll live that long.

Consider also the current "C++ API" for QtQuick. You can create any QtQuick component in C++ and position it with code like the 
following (exercise for the reader, write the equivalent code for QGraphicsView and compare):

QQuickCanvas canvas;
QQmlEngine engine;
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0; Rectangle{}");
QQuickItem* item = qobject_cast<QQuickItem*>(component.createObject());
item->setX(10);
item->setY(10);
item->setWidth(10);
item->setHeight(10);
item->setParent(canvas);
canvas.show();

I think that code is pretty bad. The only material difference to the above ugly code that we'd get by exposing the C++ API as it 
stands would be to replace the three component lines with QQuickRectangle* item = new QQuickRectangle; I really don't think that's 
good enough to compete even with a stagnating QGraphicsView - which is still available (and can be maintained if anyone really 
wants that, as defined by providing patches). Since we have QGV still, it also doesn't make sense to just copy it.

Honestly, I think that 
component.setData("import QtQuick 2.0; Rectangle{ border.color: 'green'; color: 'fuchsia'; width: 120; height: 120;}"); 
is already a little nicer than the QGV equivalent of 
rectangle->setPen(QPen(Qt::green)); rectangle->setBrush(QBrush(QColor("fuchsia"))); rectangle->setGeometry(0,0,120,120); 
Especially if you're going to have it all on one line like I do ;). I'm not a paragon of coding style though, and that's a highly 
subjective point.

The real point is: Is it such a C++ API really that valuable? Do you want a C++ API just like QGraphicsView? If so, why aren't you 
happy with QGraphicsView? If not, perhaps you can help us find the perfect C++ API for QtQuick so that we can finally expose it?

--
Alan Alpert
Senior Engineer
Nokia, Qt Development Frameworks



More information about the Development mailing list