arcade.gui.UIBoxLayout.height value is incorrect at init
Closed this issue · 3 comments
Bug Report
System Info
Arcade 3.0.0.dev20
vendor: NVIDIA Corporation
renderer: GeForce GTX 1660 SUPER/PCIe/SSE2
version: (3, 3)
python: 3.10.10 (tags/v3.10.10:aad5f6a, Feb 7 2023, 17:20:36) [MSC v.1929 64 bit (AMD64)]
platform: win32
pyglet version: 2.0.5
PIL version: 9.4.0
Actual behavior:
arcade.gui.UIBoxLayout.height
is not set immediatly after adding children to the box. It remains at 0, despite children having non-zero height.
What is also weird, it changes to a correct value during runtime after several frames, but I wonder why exactly after that number of frames.
This is the output of the code below. You can see attribute being set on frame 3:
v_box height after init: 0
v_box children heights after init: [50]
v_box height after frame 1: 0
v_box children heights after frame 1: [50]
v_box height after frame 2: 0
v_box children heights after frame 2: [50]
v_box height after frame 3: 50
v_box children heights after frame 3: [50]
v_box height after frame 4: 50
v_box children heights after frame 4: [50]
v_box height after frame 5: 50
v_box children heights after frame 5: [50]
Expected behavior:
height
attribute is set to a correct value after adding elements to the layout.
Steps to reproduce/example code:
import arcade
import arcade.gui
class MyView(arcade.View):
def __init__(self):
super().__init__()
self.ui = arcade.gui.UIManager()
self.ui.enable()
self.v_box = arcade.gui.UIBoxLayout(space_between=20)
start_button = arcade.gui.UIFlatButton(text="Start Game", width=200)
self.v_box.add(start_button)
self.ui.add(self.v_box)
self.frame_count = 0
print(f'v_box height after init: {self.v_box.height}')
print(f'v_box children heights after init: {[child.height for child in self.v_box.children]}')
print()
def on_draw(self):
self.clear()
self.ui.draw()
def on_update(self, delta_time: float):
self.frame_count += 1
if self.frame_count in (1, 2, 3, 4, 5):
print(f'v_box height after frame {self.frame_count}: {self.v_box.height}')
print(f'v_box children heights after frame {self.frame_count}: {[child.height for child in self.v_box.children]}')
print()
if __name__ == '__main__':
window = arcade.Window(800, 600)
window.show_view(MyView())
window.run()
Hi,
UIWidgets live within the GUI lifecycle. The docs contain some description regarding that behaviour: GUI Concept
UILayouts change their size depending on the space they get. The steps to calculate all of this is executed before drawing on screen.
In your code the on_update
is executed before the first draw call. Which explains, why the height is changed after the second on_update
call. In between the ui.draw()
was executed, ensured a up-to-date layouting, which actually sets the size.
If you want, use self.ui.execute_layout()
after you added the box to the UIManager.
class MyView(arcade.View):
def __init__(self):
super().__init__()
self.ui = arcade.gui.UIManager()
self.ui.enable()
self.v_box = arcade.gui.UIBoxLayout(space_between=20)
start_button = arcade.gui.UIFlatButton(text="Start Game", width=200)
self.v_box.add(start_button)
self.ui.add(self.v_box)
self.ui.execute_layout()
self.frame_count = 0
print(f'v_box height after init: {self.v_box.height}')
print(f'v_box children heights after init: {[child.height for child in self.v_box.children]}')
print()
...
That should lead to your expected result.
Please close the issue, in case your question is answered.
Thanks for the explanation.