Introduction to Qt / QML (Part 31) - Collapsible Sections

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Welcome back to Programming with Qt and QML. I'm Jesper Pedersen from KDAB. I'm gonna show you a small trick in this video. It's not really all about ListView. It's not really all about...well, it's really just a small trick. One day you might need exactly this, and then remember you saw it here first. We saw in the previous video that we had in the ListView the concept of sections and now the question that might arise to you: Can I collapse those sections, and if I do, well...how would I do that? That's what we're gonna see here. So, if you have a look at the code, or look at the user interface, you can see clicking here on the items or the sections will collapse and expand these sections. So how did we go about doing that? Let's investigate the code. First off, I got a ListView. I got a property var collapsed here. We'll get back to what that does in a second. I set up width and a height. I said focus: true, flip: true, all those things that we do every time we have a list view. The model - remember list views are associated with models - so the model here is an instance of name model...f2 to jump to that one. It's just a list model, just like we've seen before. Name and team for specifying the items in here. Then we got a delegate. Remember the delegate is what is painting each of the items in our list view. So let's see what that one...again this time I've taken my delegate and put it into a separate class or separate element called name delegate. It's not very complex. It's a text element. Clipping is turned on. The text is model.name. So, that's a name for the given element. The font size is 24 pixels. I got a new property here called expanded and I'll use that property for the height of the element. That's where the core of this whole collapsing ends, showing you again it comes from mainly that the height of the element depends on expanded. If it's not expanded, the height would be zero pixels, meaning your element is going to be rather small. And observe clip: true - had I not had clip true I would still have seen the text despite it being zero pixels high, so that's really required here. And the implicit height of my element is the other alternative. So when it's expanded, it should be what the text element itself thinks is a good size, dependent on the pixel size up here. I also have this behavior on height, and the behavior on height is what makes it slowly collapse. Well, 200 milliseconds is what it takes for it to collapse. Without that it would just go [mimics two quick collapsing sounds]...showing up and collapsing. So that's an example of this behavior that we've seen in a previous video. So that is a nameDelegate element itself, but it's also customized from the usage of it. I anchor it...there's nothing new there. The expanded - that was that property that it had that we just discussed - that one comes from the ListView itself. Its section expanded and if I scroll down here you can see I got four functions for configuring all of this. So we'll see those after we've discussed the other things. So its section expanded with model.team. So I go to the model for this particular element that I'm creating here. I ask is that particular team expanded, and if it is well then my property expander will be true. Otherwise it will be false. Just a small observation in here, my read-only property list view here, we saw that in a previous video. That is the list view that this delegate is connected to, but I could just as well have referred to list view and I actually do refer to it inconsistently throughout this code here. Just so that you will not get too confused about that. My mouse area that is sitting inside of each of the delegates, whenever I click on it it will toggle the current index. It has nothing with the expansion or not. I got a highlight...similar, has nothing to do with what we're talking about here. That's just the set up of this element in general. Now we've got a section here, that is the section for each of the elements. Remember, I got my each of the elements set up with a delegate and then the text at the top of each section is set up with the element that is specified in my section property. So my section property here says that it's...just... so the section...yeah...I asked...see that's interesting I was looking for section: here, but it's of course a combined properties of section dot property team section dot criteria view section full string. And section dot delegate, that's the delegate of the section. Section delegate is again an element that is created here on its own. It's a rectangle. It has a color, it has an implicit height here. It got the text which is just an alias down to the text element down here. And it has a mouse area building. Whenever I click on the item, it says parent.clicked. That's the signal that I have up there. So the signal clicked will be emitted from the section delegate. I set up the text of my section delegate using the section that comes from my element and unclicked. So whenever I click on that section delegate it will emit its unclicked signal, which will then go to the view. So that's where we are. Inconsistent with the previous, we have the underscore underscore lv, but here I just go directly to the view. View.toggleSection, with this name. So that's each of the building blocks. Now we just need to see the JavaScript that connects all this together. Up here at the top, I have a property var collapsed that is an object map. The syntax here is slightly weird. I'll put a link in for you to read up more on that particular syntax. But it's a JavaScript object and so it's basically just what you from Qt think of a Qmap or a Qhash. And this section expanded. All it does is that it takes this section and looks. Does my object actually have that key? And if it does, that means that it's collapsed. And if it doesn't, it means that it's expanded. So my...is section expanded...I use that on my delegate here... expanded...this section expanded for that particular element or that particular section. Then whenever I clicked on a section here, we executed the toggle section, and what toggle section does is test whether the section is expanded. If it is then hide the section, otherwise show the section. And hide the section show the section simply take...the show the section takes the element and removes it from the collapsed map and the height one puts it in. So it's a double negation that can be difficult to explain. And then the last little thing here is that I emit. There's no emit keyword on the QML side. But this is emitting that signal called collapsedChanged. Remember, I got a property up here that's called collapsed. Whenever I have a property, there's a changed signal for it. And this is the first time. This is the very first time in QML that you've seen that you actually need to emit signals like that yourself. Of course, if I created a signal myself I would need to emit it. But the changed signal - usually whenever you assign to a property the changed signal will be emitted on its own. So why do we need to do it here? Well, the key thing is that what we have here is a map and it's one of the items inside the map that is changing. It's not the whole map, but that's what we want. We want the changed signal for that whole map to emit it. That's why we need to run this signal ourselves - to emit the collapsed changed signal ourselves. And once we do that, everything fits together. I am toggling. I'm double clicking on an item. The item goes down to either...well it goes down to toggle selection, which will either hide or show, which will either remove it or put it into the collapsed map based on that map, or after that my collapsed changed signal will be emitted. When the collapse changed signal is emitted all of my expanded here will be re-evaluated because they are is section expanded, which is a JavaScript function that is depending on that particular collapsed. So again, our property binding is a beautiful example of how the property binding implicitly works in our favor. I just say it I wanted to be expanded if this item is in this map. And then whenever I added that, then my property binding will be re-evaluated because the changed signal was emitted. And then the element or the property binding is re-evaluated, which means that the element for setting that up will now change its height and because of my behavior element in there it will semi-slowly collapse or expand - truly beautiful, if you ask me. Let's end on the high note.
Info
Channel: KDAB
Views: 4,955
Rating: undefined out of 5
Keywords: KDAB, Qt, QML, Tutorial, Programming, UI, User Interface
Id: tpEKJjckHys
Channel Id: undefined
Length: 10min 36sec (636 seconds)
Published: Thu Jun 11 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.