Thursday 25 April 2013

Qt Layout Tutorial - Part III

And here we are, in the third - and last - part of our Qt layout tutorial.

As I was preparing this post, I realized one of the group boxes we added in part I, namely the group box corresponding to area B, is not actually necessary. So, we're going to remove it (you may want to refer to part I of this tutorial, since I'll be using the names I defined there):
  • Drag group box B1 to area A. The group box corresponding to area A should "light up" its entire area, to show it has the focus and that's where you'll drop the dragged widgets.
  • Do the same with group box B2 and the vertical spacer (assuming it didn't disappear, see part II).
  • Delete the now empty group box on the right. If you did this before performing the previous steps, you'd delete the group box and everything it contains.
  • Place the group boxes and spacer back where they were.
A very important note: Before you start applying layouts, make sure area B is the exact size you want it to be. When you apply layouts in area B, it should cause a minimum amount of resizing.

So, let's finish this.

As we apply layouts, all the already existing layouts should become perfectly aligned and identically sized, and the widgets' size and position should keep their expected values. If that's not the case, then you need to review the properties on the widgets.

1. Select group box B1 and apply a vertical layout. Do the same with group box B2.

You may have to do some tweaking at this point - e.g., I've had to tweak the spacer in the 2nd row of B1, in order to get the 3 push buttons to the same size as the buttons in B2.

Notice that the push button in row 6 of B2 fills one whole row. If you don't like it, you have several options:
  • If you want the button aligned to the left of the group box, change its sizePolicy.HorizontalPolicy to "Fixed" or "Maximum". You can then set the button's minimumSize.Width to set its width.
  • If you want the button in the center of the row, you'll have to add 1 horizontal spacer to each side of the button. However, you'll have to do this BEFORE you apply the vertical layout to group box B2, because once the button is in a vertical layout, anything you add can only go above or below the button. So, just press "undo", add the 2 spacers, select all 3 widgets, and apply a horizontal layout.
  • If you want the button aligned to the right, follow the procedure in the previous point, but add only 1 spacer, to the left of the button.
If you add spacers, remember to set their sizeType to "Minimum", or area B will expand later.

2. Select the two groupboxes (B1 and B2) and the vertical spacer on the right side of the form and apply a vertical layout. This should give you both group boxes perfectly aligned, one below the other, and all the layouts within each group box (and, consequently, the widgets within each layout) should also be perfectly sized/aligned. If it doesn't - e.g., if some push buttons become larger than others, then... you've guessed it, it's time for some more tweaking.

I needed some tweaking on 4 of the push buttons that were aligned at the right side, and I've decided to change the maximumSize.Width on these buttons, instead of fine-tuning the spacers.

Area B is done, now let's turn to area A. My original idea was that it would contain a single widget, e.g., a label, that would grow and shrink as we resized the form. However, I've decided to complicate matters a bit. Instead, it will contain two widgets, a list widget on top of a text edit widget. The list will resize horizontally, but not vertically; and the text edit will resize both vertically and horizontally.

3. Add a list widget and a text edit to group box A.

4. Select the list. Its sizePolicy.HorizontalPolicy should be "Expanding". We'll set its sizePolicy.VerticalPolicy to "Minimum".

5. Now, select the text edit. Both sizePolicy.HorizontalPolicy and sizePolicy.VerticalPolicy should be "Expanding".

6. Select group box A and apply a vertical layout.

When you resize group box A, this is what should happen:
  • When the group box resizes horizontally, both widgets should resize accordingly.
  • When the group box expands vertically, the list may expand, but should stop doing so at some point, and only the text edit should keep expanding.
  • When the group box shrinks vertically, the edit box should shrink and, after some point, the list should begin shrinking, too.
When we apply all layouts, the list will stop resizing vertically.

Area A is done. It was a lot simpler because we didn't want to fine-tune our control of the widgets in this area. Keep this in mind when designing your UIs - the less control you want over size, position, and resizing, the better.

7. Before we turn to area C, let's select areas A and B and apply a horizontal layout. When you resize this layout, area B should move, but always keep the same size, and area A should maintain the resize rules outlined above.

Also notice that as you shrink this layout, either vertically or horizontally, all the widgets eventually get shrunk to oblivion. Don't worry, this will be solved soon.

Now, area C. Since I don't know very well what I could place here, I'll keep it simple - just a text edit that will resize horizontally, but not vertically.

8. Add a text edit to area C. Set its sizePolicy.VerticalPolicy to "Minimum".

9. Select the group box C and apply a horizontal layout.

10. Finally, select the form or its top widget (e.g., if it's a QMainWindow, you can select the main window or the central widget) and apply a vertical layout.

Build and run! You may need some additional touches. I did, had to tweak the sizeHint.Width on spacers to get all the buttons properly aligned.

Anyway, it's ready! Get a liquid beverage (as opposed to a "solid beverage", obviously) of your choice and indulge in as much rejoicing as legally permitted. And, while indulging in said rejoicing, notice that if you try to shrink the form it eventually stops - e.g., area B acts as a vertical break, it will stop shrinking when the vertical spacer on bottom reaches 0.

I hope you've found it useful, and not overly boring.

I'll end by saying, once again, that this tutorial is based mostly on trial and error. While I've advised certain values for widget properties, the same effect can be achieved using different values. And, naturally, there may even be a faster/better way of achieving this. And, if you happen to know of such a faster/better, you're welcome to drop me a line on the comments.

You can find the files here.

No comments:

Post a Comment