Cannot get the correct size of MarginContainer

Godot Version

4.3

Question

I want to resize the Control node according to its child node MarginContainer. But it keeps using the old size rather than the changed one. The construction of nodes is like below:
Control - MarginContainer - Label
The size of MarginContainer can be automatically changed by Label. But it seems like there is a ‘delay’ in getting the new size.

func resize(text:String) -> void:
	label.text = text
	size = margin_container.size * margin_container.scale

It only works well when I repeat the size calculation code like this:

func resize(text:String) -> void:
	label.text = text
	size = margin_container.size * margin_container.scale
	size = margin_container.size * margin_container.scale

Why is this happening?

If you change the parent “Control” node to another “Container” node (e.g. another MarginConteiner with 0 margin on all sides), does that achieve the behavior you want? Or even delete the “Control” node and use the “MarginContainer” directly.

I was having a similar problem and couldn’t fix it by changing the size in code, but this approach worked for me.

There’s a couple facets to this of which I’m not going to pretend I fully understand.

  1. Size and minimum size is cached.
  2. Updating size is pushed onto a queue and processed later.
  3. Difference between minimum size and current size.

Setting text on a label pushes a message to update size on a queue. The size needs to be invalidated. It is not updated immediately. Containers wait for notifications to sort their children.

The queue is flushed and processed at key points of the current frame.

In this specific case, labels can have known a minimum size by calculating font and line metrics to determine the expected minimum size of the rendered text. So you can use get_minimum_size() instead of size:

func resize(text: String) -> void:
  label.text = text
  size = margin_container.get_minimum_size() * margin_container.scale

The general, maybe more correct, workflow would be to wait for MarginContainer to emit the resized signal:

func _ready():
  margin_container.resized.connect(_on_mc_resized)

func _on_mc_resized():
  size = margin_container.size * margin_container.scale

func resize(text:String) -> void:
  label.text = text

Although now the resize function is misnamed :slight_smile: .

1 Like