Introduction to Qt/QML (Part 46) - Exporting Values from C++ to QML

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hi. I'm Jesper Pedersen from KDAB. You're watching  Programming with Qt and QML. We've now made it to   the integration section. We're going to talk about  how we get our values from the C++ level   up to the QML level. We'll talk about  how we export QObject subclasses --  those QObject subclasses which have  properties -- from C++ up to QML.  We'll talk about how we create new elements  that do not have a visual appearance that could   be a timer, for example. We have a timer on QML,  but our example will nevertheless be a timer,   just because we were first. We had that in  training material before it was in QML. It   can't be bothered changing that. And, at the end of  this section, we'll talk about how we create new   visible QML elements. So, how do you create your own   element that is not just a composition  of other elements on the QML level, but   where the painting is done in the C++  level. So, we got four very interesting   videos coming up here. You already started  on the first one. So, please do enjoy the ride. We'll start out talking about how we export a  value -- just a simple value -- from C++ to QML.   To do so, we obviously need a C++  application this time. So,   in the previous module, we've seen all  the engine room stuff that   needs to be going on to be able to do this. We've  seen the modules before that. We've seen a lot of   stuff on the pure QML side where we had no C++  stuff going on. But now we'll merge the two,   and that, of course, requires that we  have C++ in our application.   Actually, this is likely the very last time where  you'll just create a pure QML application. You will,   from this day on, very likely start having a C++  backend in your QML application. The reason   for that is that your application is not going  to be a toy application. At least, that's my   estimate. You've been hanging on so long. So, you're  likely not going to be just doing a very simple   "Hello World" kind of application. You connect your  application to some backend code that is happening   in C++. So, to do this, the first thing we need to do is  export the values that we want in QML, from C++. To export them, we need  to get to the rootContext, and the rootContext   is like the global namespace in QML.  That's the last resort for your QML interpreter,   when it's trying to look up a value, look in the  element, and look in the root element. And then,   at the end, it will look at the rootContext. So,  that's your global variables that you have in QML.   We get to that rootContext simply by going to the  engine and asking the engine for the rootContext.   Today, you could even have setView.rootContext  because there is a method on the   view that gives you the rootContext directly. But  I just wanted to show you that we have the   engine in there and it's, of course, the engine  itself that knows about the rootContext. Now,   when I have the root context, all I need to do to  export a value up to the C++ level is to call   setContextProperty, give it a name, and give it  a QVariant value. So, the names, as you can see   here, they all start with an underscore. That's  purely a naming convention, so that, when I'm   in the QML file in which I see something starting  with underscoring, I know right away -- yes, that   thing came from the C++ side. So, I don't start looking  around in my files for where aString is defined.   The value over here, as I said, is a QVariant.  You've seen in a previous video what   QVariant is about, and you also saw in those  videos that the QVariant class actually has   a number of constructors taking different types  that are built into Qt Core. So, a QString, a   QSize, a QColor -- I do not need to wrap  them in QArea and :: from value. I   do not even need to wrap them in QArea and  QString ("KDAB").  That's all happening in C++. That's  just our regular type conversion in C++.   That's all that you need to do on the   C++ side to export your new values   into your QML. On our QML side, I don't  need to do anything special. I just   use them as if they were regular properties that  were in scope, one way or the other. So, you can see   I have a rectangle here. My width  and the height of the rectangle   simply come from this size aSize that I exported  from C++. And aSize is actually a compound element that has sub-properties in it , namely,  width and height -- so, therefore   width: _aSize.width and similar for height.   My background color is, on the other hand,  just a regular JavaScript color, when we   we have it up in JavaScript -- so, color:  _background. Now, the key thing in   this example really comes down on this line here,  where you can see that I print out aSize. So, you   look up here aSize is actually a QSize  800, 600. We could dot our way into it,   like we did on these two lines, but I can also  just print out aSize because, behind the scenes,   C++ and Qt will know how to convert these  combined elements into something that we can   use as a string. And let's just run the  example here, just to see that it actually   does -- exactly what we had. So, here is my main, again.  You can see there isn't really much hidden   in the slide I'm creating my Q application.  I'm setting my source and I'm showing my   view, so that we can actually  see something, and my main.qml.   There isn't anything hidden here, either, except  that I anchor my column inside my   rectangle. Here, you can see the application  running. It is 800 by 600. You'd have to count the   pixels on the screen for that to validate it. The  background color is gray, as I said in C++. And   down here, the size: QSize 800, 600. So  that's the string version of that size. As I said, the simple values that we have in C++  map to similar simple values on the QML side. So,  a number or string will just be a number or string   on the QML side. Our compound values    from C++, you can dot  your way into them, as long as Qt knows about   them. If Qt doesn't know about them, then you can  still send them up there. But, all you can do on the   QML side is give them back into C++, which  might still be useful in different situations.   But, if you want to be able to use your compound  values on the C++ side, all you need to do is   make them into gadgets. This is a place in the  training where I always ask myself if I am really   the only one who thinks about inspector gadget when I see Q_GADGETS? So, "Go, Go Gadget arm." There we are. Gadgets are not QObjects. So,  let me move the cursor around for you. Observe here:   class Person. And then, look at those pixels I'm  hovering over here. They do not say :public   something. It's just a regular value class, a  value class that has these three parameters.   As always, it needs a copy constructor, default  constructor, and an assignment operator. But once you   have those, you can take that and give it to QML,  and QML will be able to access its properties.   If this syntax here is new for you, then maybe you  should rewind and watch the video on properties   that we did three videos ago. What it says here  is that this object   that, on the QML side, is accessible has a name.  The name is QString. And, whenever you read that,   it actually goes and reads the m_name.  You can even assign to it to the the gadget but, as   we'll see in the example below, that value doesn't  make it into C++ land. Again, it's a copy   that you get of gadgets onto your QML level. I got  another one here in age, again, MEMBER m_age.   Do notice that, if you look at that line again -- don't look at my face, look at that line again --   notice it does not say anything about a notification  signal. That is only for objects. We'll see that in   the next video. But, for gadgets, they are a pure  copy that you get from your C++ level   up to the QML level. The QML level can  work with that. It can even update it.   But if you want it back into the C++  level, you need to call a setter back on it.   So, they are really just a copy that you get on. And,  of course, it also, without the notification signal,   means that they will not be able to participate in  a property binding, simply because it's property   binding requires that you have notification  signals for whenever the value changes. So, they   really should just be thought of as your QSize  that we saw on the previous slide.   QSize has a width and a height, and you  can take the size and give it up to the QML level,   and think of it as if it was just a value.  And that is what your gadgets are. To support that the gadget will actually be able  to print out just like our QSize printed out (it printed QSize (800, 600  as a string), we need to   create a two-string method that returns a QString.  If that method exists, the Qt   QML engine will use that whenever you try to  stringify your QML value. And that's one thing here,   on this example, we haven't seen before, namely, the  Q_INVOKABLE. What that means is that   this method should be callable or invokable from  the QML level. On the QML side, I got a Person   gadget here now, and because this method is  Q_INVOKABLE, I can call the toString on   that object. Hadn't I had Q_INVOKABLE,  QML wouldn't even know about this because   the meta-object information extracted from  moc and all of that stuff will only extract   information about the Q_INVOKABLE  and...slots? I was just about to say slots, but   slots is something that goes along with   QObjects, and our gadgets are not QObjects. Let's just see this example, here, in action. So, I got my main, my quick application, here. I  set a ContextProperty called _santa.   That is a person that is called  Santa and is 256 years old.   So, our personal constructor here,  as you can see, has a name and age. That person, of course, needs to go into a   QVariant. So, I'll say QVariant:: from   Value. I couldn't just give it as I did with my  integer and the size, and so on, because there's no   QVariant constructor that takes a person. So,  I need this QVariant::fromValue   to get it up on the QML side. I also  export a database, here. So, my _db   is database, and I'm a bit ahead of  myself because that one is a QObject.   But it's simply to export something where I can  actually access the properties and method later on. On the QML side, it looks like this. Let me just run the  application, here. It's a pretty boring   application; it has one text element that says "press  me" and, when I click it, it   doesn't even do any animation or anything. And it  doesn't seem to be doing anything except that. Well,   on standard output, it prints some stuff. So, let's  just resize this a bit. There we are. So, on standard   output, it printed out this stuff. And that's  what you can see up here. I got my item here. It   has a width and height and, inside, it has a text  element, and a mouse area where the   unclicked says, "Well, okay." So, when I click this, I  will do a global lookup, initially. So, I'll simply   console.log my _santa. My _santa  says Person(Santa, 256). So, that's printing   out that my santa is a 256 year old. Now, let me  try and get a gadget from the C++ level   onto the QML level. So, I call this _db,  which is my database. It has a method called   "lookup," and I look up the fake santa. And I  have that as a variable here on my   QML side. And  var santa equal to looking up fake santa. I can   print him out too, and I do so here. My fake Santa  is 65 years old and is called Fake Santa. I can   add a person to the database. So, I can create  new elements there, but I cannot create -- at least   not yet (I haven't seen that and, for gadgets, I  wouldn't even be able to do that) --    elements by simply going to the database to ask  if it can create it and then give it back right away.   So, here, I call db makePerson. So, I'm creating  an instance of Jesper that's 18 years old.   If that's me, then I'm afraid that's   an earlier version of me, likely before QML   even existed. I create that element, there,  and it returns that element to the QML level. I   give it straight back into the  C++ level by simply calling addPerson   with that gadget that I created, there. And now,  I can look up in the database. I look up Jesper   and, looking him up, I print him out. And we can  see here that, in the database, we got this   Jesper version that is 18 years old. On the  QML side, I can dock my way into gadgets,   as we discussed: jesper.age = 44.  And we'll print that out   and we see we have Jesper that is 44 years old.  Again, this is a slightly older example, I'm afraid.   Finally, I will go to the database and I will ask  for Jesper, once again, just to validate that    my updating him on the QML side didn't actually  touch the database. So, I'll ask for Jesper, again.   I'll print that out, and we can see that the 18  year old version of Jesper still exists in the   database. So, again, gadgets are really, truly just  values that you copy from the C++ side up   to the QML side. You cannot do property bindings  with the properties of the gadgets. You can just   dot your way into those elements. That's it  for this video. In the next video, we will see   a QObject pointer being exported. And that's   a completely different story on what you can do  with those. So, stay tuned. Until then, have a great day.
Info
Channel: KDAB
Views: 4,807
Rating: undefined out of 5
Keywords: QML, Qt, C++, KDAB
Id: quFciLDIxUw
Channel Id: undefined
Length: 16min 42sec (1002 seconds)
Published: Wed Jan 27 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.