ppizarror / pygame-menu

A menu for pygame. Simple, and easy to use
https://pygame-menu.readthedocs.io/
Other
544 stars 141 forks source link

Provide way to disable render until all widgets have been added? #439

Closed bluefish2020 closed 1 year ago

bluefish2020 commented 1 year ago

Is your feature request related to a problem? Please describe. I'm using a two column menu with 20 rows. Each time a widget is added _render() is called Adding the widgets has gotten noticeably slower (over half a second).

Describe the solution you'd like Maybe there is some other way to do this but so far the most effective approach I have tried is adding a flag to exit Menu._render() before doing any work. After all the widgets have been added _render is re-enabled and everything seems to work fine. This does defer all of the height/width checks which might make it more tedious to fix the layout. Leaving the render flag on during development should make working around that drawback acceptable.

Describe alternatives you've considered I tried widget.hide() after each menu.add.label() which did not help much, and I expect un-hiding will force new renders anyway. Setting center_content=False also helped a bit, but not enough. I did not find any existing early exits from the render calls.

Additional context I thought my issues were related to using a mess of images/tables/frames but it looks like it is mostly driven simply by increasing the number of rows.

(proof of concept code: disable_render.py.gz )

Adding labels like this:

for c in range(columns):
    for r in range(rows):
        label = menu.add.label(f'Col {c}, Row {r}')

produced:

11 rows... 0.122 s 21 rows... 0.497 s 31 rows... 1.309 s 41 rows... 2.583 s 51 rows... 4.621 s 61 rows... 7.556 s 71 rows... 11.519 s 80 rows... 16.113 s

The same loops but with _render disabled while widgets are added:

11 rows... 0.030 s 21 rows... 0.046 s 31 rows... 0.071 s 41 rows... 0.108 s 51 rows... 0.161 s 61 rows... 0.214 s 71 rows... 0.270 s 81 rows... 0.338 s 91 rows... 0.408 s 101 rows... 0.471 s 111 rows... 0.557 s 121 rows... 0.624 s

I did not check if de-duping renders in _widgetmanager._append_widget() helped when self._menu is the same object as self._menu._current on lines 371 and 376

ppizarror commented 1 year ago

Hi! This is a nice addition, check out #440. I've added Menu.enable_render() and Menu.disable_render(). The new test test_menu_render_toggle checks both widget positions are the same if disable/enable render.

Results:

Render on: 3.29s, off: 0.19s (150 widgets)

Let me know if this PR solves your issue 😄

bluefish2020 commented 1 year ago

Awesome, I'll take a look tonight.

bluefish2020 commented 1 year ago

That works perfectly. Thank you!

ppizarror commented 1 year ago

Uploaded v4.3.4 to PyPI 🍺, just update with pip.