• Godot Help
  • Help with Box Containers and Nested Controls

I'm having trouble understanding how hbox/vbox containers perform layout on controls. I've read the docs, I've done several tutorials, and yet when I try to use containers to achieve my own designs, it never works the way I think it should.

Example: Let's say I want to have 2 rows of controls, and for simplicity let's make all the controls labels, so I want something like this:

label 1 label 2
label 3 label 4

(I know I could use a grid layout, but I'm trying to understand hbox/vbox interactions)

So I create a scene tree like so:

Everything works as expected. But if I instead nest the labels inside their own controls, then the labels all align centered at the top of the main window

What do I need to do to make this scene look like the first one?

Simple example: (I would have uploaded the .tscn file, but that's not allowed)

[gd_scene format=3 uid="uid://bjvtascd4ur64"]

[node name="Control" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

[node name="Control" type="Control" parent="VBoxContainer"]
layout_mode = 2

[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/Control"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

[node name="Label" type="Label" parent="VBoxContainer/Control/HBoxContainer"]
layout_mode = 2
text = "label 1"

[node name="Label2" type="Label" parent="VBoxContainer/Control/HBoxContainer"]
layout_mode = 2
text = "label 2"

[node name="Control2" type="Control" parent="VBoxContainer"]
layout_mode = 2

[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/Control2"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

[node name="Label3" type="Label" parent="VBoxContainer/Control2/HBoxContainer"]
layout_mode = 2
text = "label 3"

[node name="Label4" type="Label" parent="VBoxContainer/Control2/HBoxContainer"]
layout_mode = 2
text = "label 4
"

    You need to order the nodes like this:

     
     ┖╴Node2D
        ┖╴VBoxContainer
           ┠╴HBoxContainer
           ┃  ┠╴Label
           ┃  ┖╴Label2
           ┖╴HBoxContainer2
              ┠╴Label3
              ┖╴Label4

    And then if you want to move the entire grid around, adjust only the top-level container (in this case VBoxContainer). The idea is that Containers automatically tile their direct children, and you build the UI by nesting Containers with different tiling behaviours.

      TwoFox Ah, silly me, I just restated your question. The reason why it doesn't work is that pure Controls don't
      tile their children. You have to code that behaviour yourself

        The reason why it doesn't work is that pure Controls don't
        tile their children.

        Ok, but then how do I create a more complicated layout, when I want more than just simple labels? I want to be able to group various labels, buttons, etc in a enclosing control, and still be able to layout everything. i.e. I want to create a main window like this:

        ...where each rectangular section is its own scene file. Which means each section would be a top-level control, and the main window should pack the various controls.

        I thought this would just be something like:

        vbox
           contol (menu bar)
           control (center area)
              hbox
                 toolbar 
                 contentpane
                 propertypane
           control (status msgs)

        but I haven't been able to make that work, so clearly there's something about container/control interactions that I'm not getting. (I keep expecting it to act similar to Qt layouts, and it's not quite the same)

          TwoFox The reason why it doesn't work is that pure Controls don't
          tile their children

          I don't think so. They should, but they're not doing it.

          The only way I've found is to be sure at one end, a child have custom minimum size property properly set. For some dumb reason, controls does not calculate themselves their children size(s), which cancel quite a bit any advantage of them.

          This video may help, it's for Godot 3.5.

          Haystack

          ┖╴Node2D
              ┠╴TabContainer
              ┃  ┠╴Label
              ┃  ┖╴Label2
              ┠╴HBoxContainer
              ┃  ┠╴ItemList
              ┃  ┠╴TextEdit
              ┃  ┖╴ItemList2
              ┖╴PanelContainer

          For the top-level containers, calculate the sizes from a script attached to Node2D or just set them manually. Set Horizontal Expand on TextEdit and set min sizes for its siblings (again, a script lets you calculate these). This is just with default Controls but the same logic applies to your custom classes: Containers on top, Controls at the bottom of the tree. And for dysproportionate layouts, expand on the biggest sibling and min sizes on the rest.

          Controls shouldn't tile their children. That's the Containers' job. If you want custom tiling, you should extend Container, not Control, and put your tiling function _notification. There's a code example in the gui docs

          Haystack Simple example: (I would have uploaded the .tscn file, but that's not allowed)

          archiving as .zip should work so long as file size is small enough(sorry I don't remember the size limit but tscn should be small enough and compress well enough).

          Haystack Ok, but then how do I create a more complicated layout, when I want more than just simple labels? I want to be able to group various labels, buttons, etc in a enclosing control, and still be able to layout everything. i.e. I want to create a main window like this:


          I'd do something like this, note I've formatted it as 'CustomNodeName(Suggested node class/type)':

          • EditorApp(VBoxContainer)
            • MenuBar(PanelContainer for BG)
              • MenuList(HBoxContainer)
                • [MenuName]Menu such as FileMenu, EditMenu, HelpMenu etc.(MenuButton)
                • ...
            • EditorArea(HBoxContainer)
              • Toolbox(VBoxContainer or maybe GridContainer)
                • Button_PencilTool(TextureButton)
                • Button_BrushTool(TextureButton)
                • ...
              • 3DViewBox or CanvasLayers(If 3D content editor then ViewportContainer, would also need a viewport as child of it and that in turn would have a scene/camera etc. under it. Or if just going for a 2D image editor here then something to contain the 'canvas layers' which would be perhaps just Color- or TextureRects, 1 per intended layer for an example so you'll be able to take advantage of CanvasItemMaterial blending modes and the node order)
              • PropertiesEditor(TabContainer assuming you might want to have multiple tabs of different properties editors in here, or perhaps also a layers manager or whatever)
            • StatusBar(PanelContainer is probably what I'd use here, might even be good to use a margin container or a HBoxContainer inside it then the text or whatever you want to do with it further)
              • Info/Hint/StatusBar(Label, RichTextLabel...) of some kind, if contained by HBox perhaps add a ProgressBar at the end here.

          N.B. You will have to drill down the inspector properties for each relevant node and make sure where relevant that the expand property is set and that nodes that need it have custom minimum size set to something other than 0.
          p.s. I'm assuming godot 4.x here but the logic isn't too different for godot 3.x either.

          Ok, I see where I was going wrong. I was still thinking in the Qt paradigm, which is very similar (except when it isn't).

          • QWidget ~= Control, its the baseclass for windows, buttons, labels, sliders, etc.
          • QLayout ~= Container, its the baseclass for HboxLayout, VboxLayout, GridLayout, etc.

          Important differences:

          Qt:

          • QLayout is not a subclass of QWidget.
          • QLayout will adjust the size and position of the parent widget in which it's embedded, as well as the child widgets.

          Godot:

          • Container is a subclass of Control.
          • Container will adjust the size and position of itself and children, but not its parent Control.

          The pattern in Qt is to pair a parent widget with a layout. e.g.
          `ParentWidget

          • Layout
          • ChildWidget
          • ChildWidget
            • ChildWidgetLayout
            • GrandchildWidget
            • GrandchildWidget
          • ...`

          So I was always pairing a Control with a Container. That's not necessary or helpful, b/c a Container is a Control.