Godot Version
V4.2.1
Question
I can’t get the size of a child control in _ready(), it always returns (0, 0). I’m expecting it to return (0, 90) in my usecase.
I’ve read previous topics about this issue. I’ve tried “call_deferred” and “await get_tree().process_frame” but they don’t work for my use case. I’ve written down what I’ve tried and their results.
A control.size() returns (0,0) when it hasn’t been set up yet.
# Part_info
@onready var item_picture_container_control = $VBoxContainer/MarginContainer2/Control
func _ready():
print(item_picture_container_control.size) # Prints (0, 0)
My control has a few layers of nested controls.
The script I’ll be showing here is ran in part_info. I’m trying to get the size of the marked TextureRect.
I read that controls get a size after their parents are _ready().
I also read the parent’s _ready() only triggers after every child _ready() has triggered, which means waiting for the child control’s ._ready() is insufficient.
So I tried wrapping getting the size in a call_deferred inside _ready(), but it still returns 0,0.
# Part_info
@onready var item_picture_container_control = $VBoxContainer/MarginContainer2/Control
func _ready():
print(item_picture_container_control.size) # Prints (0, 0)
call_deferred("print_container_size") # Prints (0, 0)
I set a break point inside the call_deferred, and the child controls weren’t done setting up.
I then changed from call_deferred wrapping to just
await get_tree().process_frame
and now it works 33% of the time.
This suggests that it takes more than one frame for all control nodes to have set themselves up.
# Part_info
@onready var item_picture_container_control = $VBoxContainer/MarginContainer2/Control
func _ready():
print(item_picture_container_control.size) # Prints (0, 0)
call_deferred("print_container_size") # Prints (0, 0)
await get_tree().process_frame
print_container_size() # Prints (0, 0), sometimes prints (0, 90) which is expected
So I implemented a loop which runs every frame, and checks whether the required control’s size is no longer (0, 0):
# Part_info
@onready var item_picture_container_control = $VBoxContainer/MarginContainer2/Control
func _ready():
await_to_be_sized(item_picture_container_control) # Consistently prints (0, 90)
func await_to_be_sized(control: Control):
while control.size == Vector2.ZERO:
await get_tree().process_frame
print("Control size: %s" % [control.size])
This prints the expected values correctly, consistently, however it feels wrong and inefficient to do it this way.
What would be the best way to handle this?