Hi. I'm Jesper Pedersen from KDAB. We are going
to sing a song for one of the unsung heroes in Qt, the class QVariant. Let's
look at some code right away, shall we? In this code, we have data. It's
an union with an integer, a double, and a char. In my classes, I always ask the students when
you would use a union and I have a lot of hands coming up. In every single class, one of those
people will tell me, "Well, see, a union is this data structure where you will only allocate as
much memory as the largest element in that union." It's, of course, entirely true but it was not what
I asked for. I asked when you will use the union. So, now we got that out of the way. When will you
use a union? Well, you use a union when you have some function where you return a value that can
be different depending on what the function did. So our typical example of this is a parser
where the first step of passing is to read the input file and it does so by tokenizing
the file. So it will read int, that's a token, then it'll read I, that's a string, and then we
read equal to zero. So, the zero part is a number. So, depending on what it will read, it will
return a different value. It'll do so in a union. That's great. That is when you would use a union.
We'll see that in at least two different cases in this training. The last case we're going to
see is our model/view, where we have the models data method returning a variant,
and the other case is our property system we're going to see in the next video.
And with our properties, we're gonna either return from C++ level a
integer or a string or a color or whatever, and all of these different ones go
into a union and return to the QML level. Let's look at this code again.
What is the problem with this code? There are actually two problems. You
can press pause now and think of it. Problem number one, and I'll bet you that in most
cases where you have used the union you have tried to solve that problem yourself. Whenever somebody
gives you a union, you cannot look at that union and say, "Hmm okay, so you put in an integer." Well you
need some enum, likely. So your unions are likely wrapped with an enum. So you'll have a structs around your union and together with the union you will have an enum and the enum
tells you, "Well, I put in an integer, I put it in a string, or I put in a whatever." So that's problem
number one. Problem number two is even worse. Line number five and a half -- I cannot highlight
that here but it's the line after number five. Pretty clever, huh? Line number five and a half -- I would
like to have my own data structures in there, but sorry we are closed for business. No more
data structures in here. "Jesper, what's up with you now? What do you mean? I'll just press
enter in my text editor and it's in there." Yes, that's what you would do, but which file
would you do that in? You would do that likely in some file deep inside the Qt code if
you want to support your own data structure. And what does that mean? That means that every
single time somebody needs to use your software, they need your special version of Qt. And every
time a new version comes out of Qt, you need to patch Qt. Are you really up for that? I don't think
so. Now let me show you a union. I actually brought one today. So, here is my very beautiful union. A
union is this thingy that I can put stuff into. Once I put stuff into my union, I don't know
what's in there but I can open it up again. But in the variant compared to the to the union --
actually, whenever I open it up, I can look into it and it will tell me what data type I
put in and, furthermore, I can extend my variants so that I can add new data types for it. Let's
see how that works in code. QVariant is a class that lives in QtCore. So, if I'm talking about
the QtCore classes, I can construct my variant by simply using a constructor that takes the type
that I'm interested in. So 42, here, has a parameter to the constructor for a variant. Now I have a
variant that has 42 wrapped in it. I can go and get that integer out of my variant again by going
to int on my variant. And here is your integer back. I can go and ask my variant what type
is in there and it will tell me as a string, "Hey, this is an integer." "i-n-t," that's
the string that will return to me. Let's just go here to the documentation
in Qt Creator and look at QVariant and you can see there are quite a few different
constructors that each take a different type here. So we've got QModelIndex. Well, we're
going to see that when we talk about model/view. We got EasingCurve; we've seen those.
We've got regular expressions. We got rectangles and lines and so on...sizes and...You
can see there are actually quite a few of those. But it's only those classes that are in QtCore,
and one of those that is not in QtCore is a color. Color actually lives in QtGUI. So, to
be able to read the color, I would need to do it slightly different. I would need code that looks
like what we have down here. So, I got a QColor. That is the red color here. I constructed my
QColor from the enum Qt::red. So I got a QColor here and I need to convert that into a
variant. I need to say QVariant::fromValue, less than QColor greater than -- but the C++ system for template overload is actually smart enough so that I do not need to write that --
and then the QColor here. To get my color out of the variant again, I need to go variant.value.
And this time there is no parameter here that it can use to decipher what the template
overload is. So I need to do that extra sit: less than QColor greater than and then
open parenthesis, close parenthesis. And I can again ask what type is in there and it will tell
me, "Hey, it's a QColor." So my type is as foreign to QVariant as QColor is. So, the question
is: How can I get my type into a QVariant? I'll show you. All I need to do is
declare my type. It's a contact in this setup here. My type needs three things: it needs a default
constructor (that is a constructor without any parameter), it needs a copy constructor, and it
needs an assignment operator. But if it has those three parameters, all I need to do is to write Q_DECLARE_METATYPE. I do that in my header file, open parenthesis, whatever
my class is called, close parenthesis. You see that down here on line 13, Q_DECLARE_METATYPE.
And now, once I've done that I can take my variant. I can put it into it. I can take my class and put
it into a variant. I can read it out of a variant. We're not going to see this for our own classes
in the next video, but we're definitely going to see that when we talk about model/view. So, stay
tuned until then. And, in any case, now you know you can put your own data structures into QVariant
and that is actually a nice thing to know. So, shall we have three hoorays for QVariant? Hooray!
Hooray! Hooray! Yeah. I'm Jesper Pedersen, from KDAB. I'll see you next time, when we'll talk
about how the property system is implemented in QML. Until then, have a great day.