 Hey everybody, this is Brian. Welcome to the 88th Qt tutorial with C++ and GUI programming. Today we're going to do something a little bit different. I got an email and I'm not going to show you who it's from. I'm just going to say her name because I don't want you crazy lunatics bombarding her with messages. But it was AD girl. Was it AD girl or AD girl? I don't know which. But anyways, she had a good point. She said hello. I've been watching your tutorials and they seem pretty cool. Notice how I'm kind of ad living here. Instead of helpful, I put cool. Anyways, she basically goes on to say Q variant seems to be the big elephant in the room. And I think she's right. I think we should make a tutorial on this because to be really honest, I didn't really get Q variant the first time I did it either. So let's go ahead and open up Qt. New file a project. Let's do console and let's call this a variant and put this in the usual location. All right. Now we've got our basic application here and we're just going to add a few includes. I'm just going to say include Q variant and let's do and include Q debug. Okay, so first off, what in the world is Q variant? Let's actually just flip out to the help here. Look up Q variant. And as you can see, and it's all its glory, we have the help system here. And if we scroll down here, it says the Q variant class acts like a union for most common Qt data types. Because C++ forbids unions and including types that have non default constructors or destructors. In most interesting Q classes cannot be used in union. What are they talking about here? Unions. Well, other languages like say Python or VBScript, I'm just going to name two popular ones. They allow you to make a value and take that value and assign it to any variable. So it doesn't matter if it's an integer or string or whatever, it just says, you know, whatever it is, assign it to that value. I'm sorry, assign it to the variable. See how confusing this gets? And that's why languages like C++ have static typing. And what's an example like int my num equals 0. That's static typing. Dynamic typing would just be saying my num equal 12. Meaning you're not actually saying what type it is. You're dynamically assigning a type to it. That's something C++ does not allow you to do. If you try to build this, it's going to explode right here on line 11. And just say int does not have a type. Actually, it wouldn't explode because we've already declared it. So there it would explode. Let's actually try to run this and see what happens here. Yeah, see my num is not declared in the scope. Meaning it wants this value type. Now the problem with that is, and you may have run into this in some of your previous projects is sometimes you really don't know what it is ahead of time. Or you need a function where it's very convenient to just toss any type of value into it and then determine later if you can work on it. So what we're going to do here is we're going to say q variant. And we're just going to call it v. We're going to say 123.02. Now those keen observers out there in YouTube land are going to realize that's a decimal value. But is it a string? No, it's a decimal. As far as c++ concern, that's a decimal. Now let's just do a little q debug magic here. We'll say q debug. And we want to v to int. So what we're going to do here is we are going to just print out the integer value of this because we're saying v to int. That's an internal conversion that it's doing. We're feeding this number here, this value, into the q variant. It could be anything we're feeding. It could be a string. It could be an integer, a decimal. You name it. And what we're doing is we're saying we want the value of this and we want it as an integer. So we're saying to int. So let's run this. And sure enough, it spits out an integer. Notice how the .02 is gone because an integer does not have a dot. That's a decimal. So let's actually go q debug. And let's just see what this thing can do here. Whoops. Help if I was typing in the right spot. You can see how it has an immense list of things it can do. Now we're not going to have time to cover all these, but you can see the conversions to byte array to care to date. So you can throw just about anything in here and get it back out. You can see there's like two rec, two size. Now you notice it does not have gooey things in there like colors. That's because it only deals with the core library. Now I know you're probably sitting there going, but what if I want to put a color in there? Well, it can do register types. So you can put a color in there. And I'm going to show you how to do a custom type here in a second. But let's do a couple more of these. Like we want to do two double. So we want to get the double back out of here. Let's compile and run. Uh-oh. Expected primary token before. Hmm. Yes, I have one too many. My silly gaming mouse gets in the way once again. And you see first one's an integer, second one's a double or decimal number there. So that's how you do that. Now what if you want to get a string out of this? You want to convert this whole thing into a string. Well, there's a nifty little thing. You can say if v dot, and I'm doing this the long way just for, you know, sake of argument here, q string. So what you're doing is you're saying can convert. And you're giving it a type. If v can convert and then the type, and notice the parentheses at the end, because this is a function we're calling, it's going to return a boolean. So if it can convert, then we're just going to say two string. You could have very easily just said, you know, Qt bug v, two string without this can convert. But we're just doing some very basic error checking here to see if can it convert. Now, word of caution here. Can convert will give you false positives. For example, if this were a string, and you were trying to convert it, you know, do a can convert into an int, it could very easily say, yeah, sure, we can convert it to an int. But when you go to actually convert it, it'll give you a zero. The reason why is because a string can be letters, numbers, whatever you want. But it is within the realm of possibility. It doesn't actually test to see if it's a value. It just said, is it possible to convert a string to an integer? So that's a little gotchy. You got to watch out for here. Let's compile and run this. And sure enough, there's 123, our integer, here's our double. And then you notice the quotes that shows you that's actually a string value, a Q string. 123.02. So there's our Q string. Now, that's fine and dandy, but let's say we want to throw a custom value in there. And we're going to actually go add new. And we're going to make a C++ class, call it my class. And we're just going to keep this pretty basic here. You know, let's just say, you know, int age, let's just call it number. And in a real world example, you'd do getters and setters and all that stuff. And this would be a private variable. But we're just going to keep this very simple. I don't want you focusing on the class. I want you focusing on Q variant. So what we need to do here is we're just going to add in a reference, or I'm sorry, add in an occlude, my class. Now let's just actually make a class here. Let's say my class and we'll just call this C class. Now we've created an instance of C class and we want to say Q variant. And let's just call this Z for the sake of argument. We'll just say Q variant from value. And there's our class. So what we're doing here is we're saying, all right, we want an instance of our class and we're making a new Q variant and we're saying from value. I mean, we're just going to sign it directly from that class. And then we want to, of course, you guessed it, get our class back. So we're going to say my class. And let's just say Z class equals Z dot value. And we want to do a type conversion here. So we want to actually say my class. And I know this looks really confusing and I apologize, but this is just kind of the syntax they use. This is generic programming at its finest, really, is what we're doing here. We're saying, all right, we've got our class. We're making a Q variant called Z. Just for the sake of argument, we could have called it fuzzy bunny slippers if we wanted to. And then we're saying, you know, call the static function from value from the Q variant class. And we're saying, okay, take this class, this guy, and shove it into the Q variant. So that Q variant will now hold that class. Now we want to make another instance of this class and we want to get that value back out. So we're saying Z value. So the value it's holding this class, but we don't know what type it is. So we have to give it the class type. Notice the parentheses at the end because we are actually calling a function. Now, here's a little gacha I'm going to show you. When you try to run this, you think everything's great and then it just explodes and says, you cannot do it. It says, Qt Meta Type ID is not a member of Qt Meta Type. What in the world is that? Well, the real main gacha here with working with Q variant is it has to be a registered meta type. I'm going to say that one more time. It has to be a registered meta type. So if you would have done this with Q color, it would have worked fine. Even though Q color is a GUI class. The reason why is because it's a registered meta type. Now, what does that mean? Well, basically what a registered meta type means is that it's registered within the meta type list inside of Qt and I admittedly don't know the internal workings of that. But everything in Qt is a Qt meta type, meaning Qt knows about all these little objects. So what we need to do here is go into my class and we need to actually register this. And we do that by adding a reference to your guest Q core. I shouldn't say reference. I know I'm going to get some hate mail over that. It's an include. Sorry. And then we want to use the macro Q declare. And we want to actually help if I typed all this out. Declare meta type my class. Now, what this is going to do is it's going to register your class as a Qt meta type. Now, notice how it's at the end of your class. It's actually not even a part of your class. Let's break that out a little bit here. So here's your class. And then after your class has been declared, we're saying Q declare meta type my class. So we're registering your class as a Q meta type. Now, run this. It should build run just fine. See, there it is. Oops. Hope if I could grab the window. There we go. We haven't printed anything out because well, of course, we haven't done anything yet. So let's take this one step further here. We'll say number equals and random number anybody 222. And then we're just going to say C class. We're going to go Q debug. And we're just going to get that value back out just to show you that this thing works. Save and run. So sure enough, there's 222. Now, how did we get to that point? Little reviews in order here. All right. Now, we have our class where we've got a public variable. We're signing 222. Don't ask me why. Just kind of how the brain was working. And then we're making a variant and we're putting that class inside the variant. Think of Q variant as a container. It's a box that you put things in. Now, when you go to get that thing that you put in the box out, you don't know what it is. You don't know if it's hot or cold. And maybe it's like a pot of boiling water. And it's too hot to hold. So you're saying, OK, what do I need to know about this class? And you say the type and it'll convert it for you. But that type has to be a Qt meta object, meaning it has to be declared using this macro. And that declares your class. See the class name as a Qt meta type. Then you can use your own classes as Q variants. And then, of course, at the very trail end here, we're just proving that this work by saying, give me the number that we previously stored in here, 222. Pretty simple, pretty easy, now that you know how it works. Now, why would you use this in the first place? Well, honestly, it's very hard to come up with an example because this is the type of thing you won't use very often. And I know as soon as I say that, I'm going to get 3,000 emails saying, but I use it for this, I use it for that. The whole point of static typing is that it's much more secure, meaning you're less likely to crash your program. If you know ahead of time, you're going to work with an end to a string or that. Q variant allows you to get around that little gotcha by saying, well, what if you don't really know what it is? For example, user input is a great thing. You've got a console application. You're asking, hey, how old are you? Well, you expect an integer. You expect, you know, 36 or 22 or 18. What if they type in 123.02? Because, well, it's just some guy who doesn't like your program. Well, if you're expecting an integer, well, don't worry, integers will just lop off this .02. But if you're strictly expecting an integer, that will crash your program. Now, I know some of you are going to say, but you could do this, you could do that. My point is Q variant makes it so you don't have to do all that. You can simply shove the value in the box, the Q variant, and then say, can we convert it? If it returns to, then you convert it into whatever you need it to work with. And let's say you have my class. Now, don't think of this as just a single class. Let's just pretend for an example, we made hundreds of classes that inherit off C class can convert, should actually return true if it's an inherited object of that class. Because it's going to go off the registered meta type. Now, I could be dead wrong about that because we haven't made hundreds of these to prove it or disprove it. But everything I've read says you can do that. Anyways, I'm babbling. This is Brian. I hope you found this tutorial educational entertaining and ad girl. If you're out there watching this, keep up the feedback. I love that question. And of course, you can go out to my website void realms.com, click tutorials, and I'm going to upload this out into the cute section. And so you'll have the source code to play around with. All right, talk to you later.