0 votes

I have a ScrollContainer with a VBoxContainer inside. I add new nodes to the VBoxContainer from code and I want the ScrollContainer to scroll to the last one from the code. This proved to be surprisingly complicated, mainly due to the fact that GUI gets updated on the next frame, so I cannot manipulate the scrollbar in the same place that I've added the node;

I tried using GrabFocus() and :

ScrollContainer.ScrollVertical = (int)ScrollBar.MaxValue;

but the first causes the scrollbar to scroll to the top and second to scroll to the previous last position.

I've read that in GDScript I can do this before further manipulating the GUI:

yield(get_tree(), "idle_frame")

and the C# equivalent would be:

await ToSignal(GetTree(), "idle_frame");

but it appears to block execution of the code forever.

How to properly await idle_frame from C# or at least wait for the GUI to have been updated (the right way).

in Engine by (55 points)
edited by

2 Answers

0 votes

It seems I can achieve this by connecting to a tree_entered signal of the added child node. By the time tree_entered signal gets emitted, GUI is already updated.


Edit: This worked when I was adding just one child node from the code, but after I started adding multiple nodes at the same time, the engine got confused and started scrolling to the top again. I'll have to figure out a better solution.


Edit: I ended up scrolling the ScrollContainer in the _Process method when a bool flag is set to true and I set this flag to true, every time I add a child node. After scrolling the ScrollContainer, I set the flag back to false. I don't know if it's the proper way to solve this problem, but at least it works.

by (55 points)
edited by
0 votes

You could use the ScrollBar's AllowGreater property:

var button = new Button {Text = $"{index++}"};
_vBoxContainer.AddChild(button);

// Disable 'AllowGreater' to get the proper 'MaxValue'.
_scrollContainer.GetVScrollbar().AllowGreater = false;
var maxValue = _scrollContainer.GetVScrollbar().MaxValue;
_scrollContainer.ScrollVertical = (int) maxValue;

var itemSpacing = _vBoxContainer.GetConstant("separation");
var offset = button.RectSize.y + itemSpacing;

// Increase the scroll position with the inserted item's height
// and with the itemspacing.
_scrollContainer.GetVScrollbar().AllowGreater = true;
_scrollContainer.ScrollVertical += (int) offset;

enter image description here
But you need to take about the AllowGreater flag. If it is enabled, it can result in unwanted scrolling behaviors (e.g.: you will be able to scroll out from the list).

by (150 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.