 Hey everybody, it's Brian. Welcome to the 122nd Qt tutorial with C++ and GUI programming and we are actually going to do a little bit of GUI programming today. Usually we do command line applications. Alright, so today we're going to cover a few things. Qconcurrent and the new signal slot method in Q5. Alright, so actually Qconcurrent is massive. We're not going to cover the whole thing. We're only going to cover the Qconcurrent run function, which is how to kick something off. And the Qfuture, which represents the result of an asynchronous computation. So let's just dive right in here, create a new project. AQ widgets application. And we'll call it my threaded app. Why not? Just because. And, next. And we're going to give it AQ dialog. Finish. So we've got our basic app here. And we're just going to real quickly lay the sucker out. We'll start. We'll call this stop. The premise of this app is we've got two buttons, start, stop. And when we click start, we want something to happen. When we click stop, we want it to stop happening. A pretty simple app. And what it is, is we're going to display a string. Oh boy, my cat just woke up. She's going to start meowing. Yeah, you can hear. We're going to display a string right here in this little line edit. Pretty simple. Pretty easy application. And we're just going to close this out. Save everything. Give it a good build. Show you what it's going to look like here. So we'll click start. Something will happen here. We'll click stop and it will stop happening. But we want that something that's happening to be threaded. Alright, so first thing we need to do is add in a reference to current. Ah, if I can spell. This tells Qt to load the Q concurrent library. There we go. And we've got our dialog and we've got our main. So let's go ahead and actually add in a slot for clicked. And a slot for clicked again. So we've got our start and stop buttons. Bear with me, guys. I've got to let my cat out of my office here. She's going to start whining if I don't. Come on, kitty. Go on. Go on. Yeah, I know. Go, go. That cat's like 20 years old and she's like the bane of my existence. But I love her. And every time she hears me talk, she just starts whining her butt off. But she's a deaf and going blind and all that stuff. So I'm going to miss her when she's gone. She hasn't been doing too well lately. Anyways, call this my job. And we're going to make a new class that's going to be under QObject. It's funny how pets kind of shape your life. You know, do your whole schedule around your pets. And we're going to add in QDebug. And we're going to add in our class. Just want to make sure we got that out of the way. And over here we're going to add in a few different things here. QDebug and QThread. If you're wondering why I'm adding QThread, we're not actually going to do the threading portion. That's all handled by QConcurrent. The point of this class is to write multi-threaded applications without using the low-level primitives such as mutexes, read-write locks, et cetera, et cetera. If you've done any multi-threaded programming or even attempted it, you know, it gets very complex, very fast, and it can be a royal pain. All right, so we want to do a few things here in our little class. First thing we want to do is emit a number. So we're going to say void on number. Call this QString, name, and int number. So all this class is going to do is it's just going to generate a number. And we're going to emit that out of a signal. All right, so we also need a start function. So we'll say void, start. Oops, can't type now, the cat distracted me. I'm all goofed up. And we want to just, for the sake of arguments, give it a name. And we want to actually make a slot called stop. Because we want to be able to stop this thing on demand, right? Private boolean, whoops. All right, so very simple class. It's got a function called start. That's when we'll start computating. We've got a signal called on number. So every time it generates a number, it'll emit the signal. And then a slot of stop. So we want to be able to stop computating. And a member variable called mstop. And let's just flesh this out real quick. It's Christmas time here. Things have been kind of crazy. We had our furnace. Let me back up. Our water heater died and it killed our furnace, if that makes any sense. It just, oh my gosh, the amount of stress we've been under is just crazy. So things have been a little stressful in this house. So we're going to say stop false and stop false. What we're doing is we're saying when the class is created, we want to set that variable to false. When we start, we want to set the false because, you know. But when we stop, that's when we want to say true. That's our variable telling us, hey, we need to stop. And we're going to actually fill in the part where we're going to compute a number. So we're just going to say 4 int i equals 0. i is less than some giant number increment i. Now the first thing we want to do is check to see if we're stopped. If mstop, then return. Meaning if we're stopped, just jump right out of this and exit the function. And then we're going to just spit this out into Q debug from thread. And we want to actually emit a number. And we're just going to emit the name int i. Now this is interesting. Computers are so fast that if we just left it as is, we would never see any. It would just go bloop and you'd just see that 99999 number. So we need to actually slow this thing down. One of the few times you actually want your computer to go slower. So we're going to call the current thread ms sleep. And ms just stands for millisecond sleep. So we're going to sleep for 100 milliseconds. If you just do sleep without the ms in front of it, that is seconds, not milliseconds. So you would have 100 seconds. So you'd be sitting there forever waiting for the next number. So that's all there is for this class. Q string usually forbids itself from being copied and it would create a new string. So I'm not sure if I should make another Q string and do that. Or pumping that out will automatically make a copy of it. But we're going to try it like this. Just know I may have to come back here and fix that. Let's give it a good build just to make sure everything's up. Yeah, that's why we build. It's called incremental build. Oh boy, what now? Stop with no type. What have I done? Avoid stop. What should work, right? Forbids declaration of stop with no type of permissions. Sometimes it helps if you actually read the error message. I'm sure we've all been there. C++ can be maddening. All right. I think it was the creator of C++ said that within C++ is a simpler language screaming to get out. Give it one more good build just because I didn't trust it. All right, good. So we've got our dialogue. We've got our class. Now we need to connect the two together. And this is where the magic happens. And let me just double check real quick where we're at. Yeah, we do need to add a few little snippets of things here. We have got our explicit create. We've got our slots. But those are private. We want to do a public slot. Slots, not slots. And we're going to say void. Q string, name, int. It's actually called new number. Why not? Why not? All right. So we also want to make an instance of our job. So we'll say my job, mjob. I called it something else in my notes. I keep glancing over. I know it's going to trip me up later, but we'll add this in. So this program, the dialogue is very, very simple. You have a start button, a stop button, and a slot for a new number. So what we need to do here in the stop button is we're going to emit. I did not add it, did I? I did not. All right, there. We should be a little better. Now we've got our signal saying we're going to stop. Let me actually lowercase that just because I'm picky. Go back in here. We're going to say emit. On stop. Whoops. So when we click the stop button, we're emitting the signal to stop. Why are we using signals and slots? Very, very brief explanation. If you've ever done GUI programming and threaded programming and you try to intermix the two, you get like, object cannot be called on different slot or different thread and blah, blah, blah. Just start throwing all these crazy error messages. Well, that's what signals and slots do is they actually traverse threads and they do it very, very well. So we're going to leverage that power so we don't have to screw around with it. Now, you are probably used to the old school of the Qt 4 Plus method where when we go to connect a signal slot, we go connect. Object, which is a pointer too. And then we go signal and then object to slot. You're used to that. We're going to actually use the Qt 5 method. So note, if you're still using Qt 4, this part will probably not compile for you. And the reason why we're doing this is I believe that they are going to phase out the old way. So I need to personally start getting better at using the new method. So we're going to give it a reference to my job because it takes a pointer, right? And then it uses a function pointer. We need to give it the on number because that's our signal. And then give it this and then a function pointer to dialogue. What did I call that? What did I call that? New number. Derp, effective win. That's not it. There we go. Now, the pros and cons of this. If you were to connect a signal and slot, and let's say this new number, you didn't declare it. This was just gone. It would still compile. But when you run it, it would say, you know, could not connect the object, blah, blah, blah. And you'd spend a day trying to figure out what that meant. Because this is more compiler friendly, it'll tell you right away if there's a problem. So I may end up checking this out. See, I've already gotten something wrong here. Expected primary expression before token. What the heck? Expected primary expression before token. What did I do here? Let's make sure that's actually the problem. Give this a good build. All right, so it is my connect. Oh, yeah, that's why. Because I'm giving it the class mjob. There we go. That should actually fix the problem. All right, build. Let's see what the Q4, it would have maybe, maybe not caught that. I don't know. Sometimes it would. Sometimes it wouldn't. Honestly, that was an accident. So I guess I just kind of proved my point that it's a little more robust and a little friendlier. So, and you can see it's not as verbose. It's not as wordy. It's not all the way out here where the cursor is. I mean, it's very simple, very easy. So anyways, we're connecting the instance of my job to a new number. So every time it emits that right here, it generates the new number. It's going to call it right here. So we're just going to queue the bug from dialogue. Pretty cool. Pretty snazzy. And then we're going to actually connect up the stop. So connect. And I apologize. I'm so not good at this. I'm still learning some of these new bangle technologies myself. Oops, we want to actually connect this. We're going to do on stop. And then you want to, you guessed it, give it a reference to my job. Stop. So all we're doing there is we're saying when the dialogue emits on stop, we're going to call stop. And if those don't line up, then it'll generate a compiler error and things like that. And it will give it a good rebuild. All right, good. So we got a good build. We've got our signals and slots connected. Now we want to actually fire this thing off in a new thread. So we're going to go queue future. We do not. We want to add our cute concurrent. There we go. That would probably make things a little easier in life, right? So say queue future. And we're going to say void because it's not going to return anything. But you could say, you know, it's returning an int or it's returning a queue string or whatever. But this is returning nothing. And what this will do is it'll sit there and wait until the result is back. And we're just going to call this test equal cute concurrent. And notice how we're calling the namespace here. We're going to say run. Now, this is where it gets a little tricky on some things. And I need to do a little explanation. Typically, examples you'll see out on the net, you're actually calling a function outside of a class, meaning it's in the main and it's a function up here. We're actually doing it within a class. So we've got to start, you know, dealing with pointers a little bit. So I'm going to say this. Help if I could spell. So we're going to give it a reference to the current object. And now we need to tell it what we're actually starting in that object. So we're actually going to say, you know, my job. And what did we call that start? There we go. Now notice how we're not passing a parameter there. So we've got to actually give it a parameter now. No, let's not call my third. That'll get confusing. Let's call it. Why not kitten? Thinking about my cat. All right, let's give this a build and then I'll explain once it's got a good build up here and going. All right, good. So we are, we've already got our object because it's created with the dialogue because it's a local variable. And we're going to say qfuture. It's returning nothing. And there's our future object. And then we're saying qconcurrent run. And what it's telling it to do is say grab this object out in memory. So we're giving it a pointer to it. And then the function pointer is the my job class start. So what it's doing is saying get this object. And then in that object, look for the function called start. And we're going to pass a parameter of kitten. Why kitten? Well, why not? So when we go up to start, you see how we've got our name. That's the parameter. We're setting stop to false. It will generate, you know, a number between one and some giant number. If it stopped at a return, otherwise it'll say from thread and that number. It'll emit the on number. Jump back into the dialogue. And because we connected our signals and slots here, it'll say from dialogue. That's a mouthful. Let's actually run this and see if it works. So we're going to start. And you can see how it's actually running in here, but it's not showing here. So let's actually stop. Now, one thing you notice how is it says from thread, but the from dialogue is not there. So meaning that thread's still running, even though I've closed the dialogue. So that's another bug we need to fix. This is some of the complexity of threaded programming. All right. So what we'll do here is we'll emit on stop. So when the dialogue's deconstructed, the last thing it does before it deletes itself is we're going to emit the on stop, which will stop the thread. And a new number. We want to say UI. What did we call that, TXT? Or is that still line edit? Yeah, line edit, set text. And we'll say name plus number. All right. So let's run this again. Click start. And it's saying kitten and there's no number. There it is. All right. Yeah. The reason why is I'll explain that. Now when we click stop, you notice how everything goes and stops. If we run this again, we click start. If we close the dialogue, everything stops. Let's fix that other one right here. Some of you already know the answer to this. Q string. It was printing the ASCII character equivalent. We want to actually convert it to a Q string. So now we go. Now you know this is threaded because when you move the window, and I don't know if the video's fast enough to pick this up, you can see the numbers changing. Many operating systems, especially Linux derivatives, when you move the window, it locks the GUI thread so that it'll quit counting. And you'll actually see it in the QTPug stop counting if it wasn't threaded. And you can either click stop, or you can just close the dialogue because we're emitting that stop. See? If you start it, it starts over. Stop. You can start it. And just close the window. And it stops. That actually, believe it or not, seems very simple, but a lot is going under the hood because we're using Q concurrent. We don't have to deal with semaphores, mutexes, Q thread pools. It's all handled for you. And it's all seamless and easy. And all you have to do is connect your signals and slots and call the run function. And the reason why I added the stop is because one of the billions of questions I get is, hey, I'm doing multi-threaded programming, but how do I tell it to do stuff? How do I tell it to stop? Well, it's just signals and slots. It's very easy. You could make another signal and slot, like connect to a socket, or print a document, or whatever. All right. So that in a nutshell is the Q concurrent future and run. I hope you found this educational and entertaining. And thank you for watching. You've probably already figured out that I have an entire YouTube channel out there with 120 some odd other tutorials. Be sure to visit my website for the source code for this and any other tutorial. I'll just go tutorials, and then you're probably interested in Qt, and I've got all the source out there. Also, I have a Facebook group called Voidrums. There's like 120 some odd, wow, coincidence, 120 some, 120 some odd of us programmers out there. Most of us are interested in Qt and other languages. And last but surely not least, be sure to visit my petprojectpluginbot.net. A lot of the code from these tutorials is actually coming from this feature. Personal Milestone, I just released the Mac version for this. So I may actually do a tutorial on how to deploy for Mac Windows and Linux, because boy, that was a pain to figure out. Anyways, that's all. Thanks for watching.