yes - pygame is barebones "we control the pixels" - and has been around a lot of time, and itself looked like abandoned for a lot of time (it was just in late 2016 that it would install clean on Python 3, for example). So, in the meantime pygame looked abandoned people moved away.
For the time being, you have to try your luck mining a usable toolkit from here:
https://www.pygame.org/wiki/gui
The PGU toolkit listed there, as you noted, seems quite complete - bar examples on how to build simple widgets to interact with an existing Pygame codebase. All the examples assume one wants to just have an stand alne gui application for form filling, which, I agree, is quite inapropriate: if one wants this kind of application, just use Tkiner, Qt or create a web app.
It turns out, however, that using a standalone widget in an existing pygame window is quite simple. Despite all the library examples calling the .run
method, which is the spoiler part, since nce you call run
the PGU app takes over and there is no way to run your code back, save for callbacks. However, the run
method itself consist of a very simple infinite loop, calling the app's loop
method. You just have to put a call to app.loop
in all frames of your own pygame loop and have the widgets working.
It will swallow pygame events, however - if you want to treat event while you are displaying widgets, you should dispatch all events to app.event
and call app.update
instead of calling app.loop
. It is trivial once you look at the source code for the app class at https://github.com/parogers/pgu/blob/master/pgu/gui/app.py
So, a complete example for using a text-input can be:
import pygame
from pgu import gui
SIZE = W, H = 800, 600
def bouncing_rect(screen):
surf = pygame.Surface((50, 50))
rect = surf.get_rect()
surf.fill((255, 0, 0))
vx, vy = 10, 10
while True:
screen.blit(surf, rect)
new_surface = yield rect
if new_surface:
surf = new_surface
rect.width = surf.get_width()
rect.height = surf.get_height()
rect.x += vx
rect.y += vy
if rect.right > W or rect.left < 0:
vx = -vx
rect.x += vx * 2
if rect.bottom > H or rect.top < 0:
vy = -vy
rect.y += vy * 2
def main():
screen = pygame.display.set_mode((SIZE))
app = gui.Desktop()
txt = gui.Input()
app.init(widget=txt, screen=screen, area=pygame.Rect(50, 50, 200,25))
bouncing = bouncing_rect(screen)
previous_value = ""
font = pygame.font.SysFont(name="Sans", size=30)
while True:
screen.fill((0,0,0))
rect = next(bouncing)
app.loop()
if txt.value != previous_value:
previous_value = txt.value
rect = bouncing.send(font.render(txt.value, True, (255, 255, 0)))
pygame.display.update([rect])
app.repaint()
pygame.display.flip()
pygame.time.delay(30)
try:
main()
finally:
pygame.quit()
(I just made the bouncing object as generator function using the "send" method, since there are very few examples of this pattern, but it could be a class just the same - if it were a common pygame.Sprite child class, I'd just call "update" instead of using next/send. )