Hi. My name is Jesper Pedersen. I'm from KDAB.
You're watching programming with Qt and QML, and we are looking at the integration between QML
and C++. Did I say QML on C++? I used to say C++ in QML. But, this time,
it's actually between QML and C++, because, in this very video, we are going to see
how we can create elements that can be instantiated from the QML side. So, it almost
feels like it's QML that is back in control. To not just export an object up to the QML level from C++, but to create a new element
that you can instantiate from the QML side, you need to do four things. First, you need to subclass
from either QObject or QQuickItem. If you subclass from QQuickItem, the element
has the option of being seen on the screen. So, in
this example, we're just creating a timer that isn't visible, but you could still
choose to make it subclass it from QQuickItem, simply because that adds some of the facility
that QQuickItem offers you, among other things component.uncomplete that we've seen a number of
times. If you subclass from QQuickItem, of course, GammaRay will tell you that you have an item
that has a size of 0,0. But, if you can live with that, that
doesn't seem like a terribly bad choice. Next step: once you have created a subclass
from QObject, or from QQuickItem, you need to actually tell the QML environment
about this new element and you need to make it possible for the QML environment to instantiate
your class because, on the QML side, there will be code that says it wants a timer. Then,
your C++ side needs to new-up such a timer. So, we need a bit of glue code for that. On the QML
side, that's step three and four. You just import the elements that you created there, just like
we've seen import QQuick2.0 or import QQuick.layout -- whatever version that was. You
will have to import your own version, or your own your own library, in that way and then you'll
just use it, just like any other QML element. So, let's see those four steps
on the slide, here. First of all, I create my timer. It's a random timer that's subclassing from
QObject. It has this Q_Object, as we've discussed so many times. It has a constructor
with the QObject pointer parent equal to no pointer. And we have my real QTimer
sitting as an instance variable. I'll get back to the discussion of why
I am not just exporting a QTimer. Why didn't I subclass from QTimer,
and am, instead, creating a completely new
object and then just having my QTimer as an instance variable? I'll get back to
that discussion in just a little bit, just so that you're at ease with that
design already, now. I could have done one of the other two, but I chose for a reason that will be
apparent to you in five minutes, to do it this way. That is the step of creating it. Of course,
I need to implement it, somehow. Now, the next step is registering it. And registering it is done
using a method called qmlRegisterType. It takes a template parameter, here, which is the
actual class that I had. So, just go back here to class RandomTimer. So, it's a class name that I
got there. And then, it takes four parameters in the constructor. CustomComponents 1.0 is what I'm
going to import on the QML side. Once I've done that, I will have access to a new element that's
called RandomTimer. It's not an entire coincidence they're called the
same, but there's nothing that requires it to be called the same. We haven't talked too much about
versioning of QML. We've seen that you can write "import Qt Quick 2.0" or "2.7," or
whatever we have throughout the code, here. So, if we had two different versions I could have
exported, I could have called this qmlRegisterType two times. One time, I was exporting Random
Timer v1 and, the second time, RandomTimer v2. And, when I exported RandomTimer v1,
it would be CustomComponents 1.0 RandomTimer. And, for the v2, it might be
CustomComponents 2.0 RandomTimer. If I had two different versions of my RandomTimer,
RandomTimer v2 was the updated, cool version that could also brew coffee underwater, or whatever it
was able to do, where I still might have code that I didn't want to touch and, therefore, I would still
want to use RandomTimer v1 in that code, so the RandomTimer here. And the random timer here
usually is the same name, but it doesn't have to be. I'll give you a link in the description below
where you can learn more about the versioning in QML. I will touch more on that in this video
series. Finally, import CustomComponents 1.0, and now I'll just use random timer as I was
using any other element: Rectangle, Item, whatever. Let's see a slightly more involving example of
this, so we can see it running and we can see the different approaches to what would
I want to subclass from. So, my RandomTimer... simply, whenever I click here, the timer is
running and says, "meebeep, meebeep," and when I click again, well, the RandomTimer stops.
My main.cpp, here, is really just what it was on my slide. I'm registering RandomTimer: RandomTimer
CustomComponents 1.0. So, let's go to my main.qml. My main.qml is instantiating this RandomTimer,
here. It sets a property on that object. So, it's just a regular QObject that I exported. And
remember, my QObject that I exported can access properties, and signals, and slots, and
Q_INVOKABLE. So, I'm setting a property on that QObject, here. It has a signal that is
called timeout. So, I'm connecting to onTimeout and, when onTimeout fires, i print out timer fired
on my console, for debugging purposes, i guess. And then I say to my beep animation, "Will you
please start running?" And my beep animation is this sequential animation we have down there.
For 50 milliseconds, it will have the opacity of my beep text go from zero to one. So, it
comes in over 50 milliseconds. And then, after that, for 300 milliseconds it will then go away again.
So, we watch again. I cannot count; you'll have to do that yourself. So, it comes in
50 milliseconds, goes away for 300 milliseconds. The RandomTimer interval came from the
timer. So it's itself, randomInterval. I don't really need to write timer.random
Interval here, but hey, that's cool. Every time it goes off, it starts this animation.
My RandomTimer class...RandomTimer.h... there's really nothing different from what
we saw in the previous video, where we saw how we can export our QObject. It's purely how we
are making it available to the QML side. So, I got Q_OBJECT. I subclass from QObject,
here. It could have been QQuickItem, as we discussed. I got the QProperty,
where I set up the interval and the active. My RandomTimer constructor, here...set
Interval and interval, they are used in my property definition, up here. I got my
Q_INVOKABLE, which is this method that I can execute from the QML side to get a random
number, here. And I got some timer set up, and so on. So, the only thing that's really worthwhile
discussing in this setup is why subclass from QObject, rather
than just subclassing from QTimer? Well, let me kill that idea first. Well, no --
I had the idea before. Why didn't you just export the QTimer? I could have exported
a QTimer. Well, first of all, this example was written in the Qt 4.8 days. So, back then, the
QTimer had not been updated with properties for active, and so on. Go and read the API documentation
for that, if you don't believe me. That's the first thing. The second thing is I actually need
more than a QTimer. I also need the randomInterval that you see here. I need that on
my QTimer. So, I couldn't just give it a QTimer. I needed an excuse, sorry. Now, the
second thing is why didn't you, then, subclass from QTimer instead of subclassing from
QObjects? Well, I'm glad that you asked. I did so because I wanted to show you the more generic way
of doing this. So, sometimes you have an object that fits straight into your QML. You can just export
that object. If QTimer had been your object, you would have likely just added that randomInterval
on that one and exported that straight into QML. It might have been that it was team A over there
that had created that object and you couldn't do that, so you'd sub class from their object,
add the the randomInterval, and export that up. But, sometimes, you have objects that might not
even subclass from QObjects that you want to to make available as new elements in QML. It might
be that you have the concept of a sensor and the sensor element is really something very low-level.
It can read data from a bus, or whatever, and you want to make them available in QML. But you're
definitely not going to get the idea of subclassing your sensor class. Subclassing that
from QObject -- you're not going to get that idea from the low-level team. So, there, you
create this proxy object that has the sensor as an instance variable. You add the properties, you add
the signal, you add the communication to the real sensor, and, somehow, the sensor will tell you that
it has changed, however that communication is done. And when that sensor data is changed, you're
going to emit a signal. So, you will have this proxy QObject between the sensor that doesn't
have anything to do with Qt, and the QML level. That's it. Now you know how to create your own
new element. They don't look like anything. That's the last little piece of the puzzle that we are
missing. How can you make your new element actually look like something? And that is the next video
that we're going to do -- the last one this module. So, please do hang in there. In just 15 minutes, you
will know how to create your own user interface element -- well, 15 minutes from when you start the
next video. If it hasn't been published already, this sounds like a good time for you to subscribe
to our channel. Until then, have a great day.