CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pyglet

Cross-platform windowing and multimedia library for Python with OpenGL graphics, event handling, and audio/video playback

Overview
Eval results
Files

gui.mddocs/

GUI Widgets

Interactive UI components: buttons, sliders, text entry, and containers.

Quick Reference

from pyglet import gui

# Frame (manages widget events)
frame = gui.Frame(window)

# Button
button = gui.PushButton(x=100, y=100, pressed=pressed_img, unpressed=unpressed_img)
frame.add_widget(button)

@button.event
def on_press():
    print("Button pressed!")

# Slider
slider = gui.Slider(x=100, y=50, base=base_img, knob=knob_img)
frame.add_widget(slider)

@slider.event
def on_change(value):
    print(f"Value: {value}")

# Text entry
text_entry = gui.TextEntry('Initial text', x=100, y=150, width=200)
frame.add_widget(text_entry)

Frame

class pyglet.gui.Frame:
    """Container managing widget event dispatching"""
    __init__(window, enable=True, cell_size=64, order=0)

    # Methods
    def add_widget(widget)
    def remove_widget(widget)

    # Properties
    enable: bool  # Enable/disable event handling
    widgets: list  # All managed widgets

Buttons

class pyglet.gui.PushButton(WidgetBase):
    """Clickable button"""
    __init__(x, y, pressed, unpressed, hover=None, batch=None, group=None)

    # Properties
    value: bool  # Current pressed state
    enabled: bool

    # Events
    @button.event
    def on_press():
        """Button pressed"""

    @button.event
    def on_release():
        """Button released"""

class pyglet.gui.ToggleButton(PushButton):
    """Button with on/off state"""
    # Same as PushButton but maintains toggle state

Slider

class pyglet.gui.Slider(WidgetBase):
    """Horizontal slider"""
    __init__(x, y, base, knob, edge=0, batch=None, group=None)

    # Properties
    value: float  # 0.0 to 1.0
    min, max: float  # Value range
    enabled: bool

    # Events
    @slider.event
    def on_change(value):
        """Value changed"""

Text Entry

class pyglet.gui.TextEntry(WidgetBase):
    """Single-line text input"""
    __init__(text, x, y, width, color=(255,255,255,255), text_color=(0,0,0,255),
             caret_color=(0,0,0), batch=None, group=None)

    # Properties
    text: str
    focus: bool  # Has keyboard focus
    enabled: bool

    # Events
    @text_entry.event
    def on_commit(text):
        """Enter pressed"""

NinePatch

class pyglet.gui.NinePatch:
    """Scalable UI element from 9-slice image"""
    __init__(texture_region, left, right, top, bottom)

    def get_subregion(x, y, width, height) -> TextureRegion

Widget Base

All widgets inherit from:

class pyglet.gui.WidgetBase:
    """Base widget class"""

    # Properties
    x, y: int
    width, height: int
    enabled: bool
    batch: Batch
    group: Group

    # Events
    def on_mouse_press(x, y, button, modifiers)
    def on_mouse_release(x, y, button, modifiers)
    def on_mouse_drag(x, y, dx, dy, buttons, modifiers)
    def on_mouse_motion(x, y, dx, dy)

Examples

Button Grid

from pyglet import gui, image, graphics

window = pyglet.window.Window()
batch = graphics.Batch()
frame = gui.Frame(window)

# Load button images
pressed = image.load('button_pressed.png')
unpressed = image.load('button_unpressed.png')

# Create button grid
buttons = []
for row in range(3):
    for col in range(3):
        x = 50 + col * 120
        y = 400 - row * 80
        button = gui.PushButton(x, y, pressed, unpressed, batch=batch)
        button.id = row * 3 + col
        frame.add_widget(button)
        buttons.append(button)

        @button.event
        def on_press(btn=button):
            print(f"Button {btn.id} pressed")

@window.event
def on_draw():
    window.clear()
    batch.draw()

pyglet.app.run()

Volume Slider

slider = gui.Slider(x=100, y=100, base=base_img, knob=knob_img, batch=batch)
frame.add_widget(slider)

@slider.event
def on_change(value):
    # value is 0.0 to 1.0
    music_player.volume = value
    volume_label.text = f"Volume: {int(value * 100)}%"

Text Input Dialog

text_entry = gui.TextEntry(
    'Enter name...',
    x=100, y=200, width=300,
    batch=batch
)
frame.add_widget(text_entry)
text_entry.focus = True

@text_entry.event
def on_commit(text):
    print(f"Submitted: {text}")
    text_entry.text = ''  # Clear

@window.event
def on_key_press(symbol, modifiers):
    if symbol == pyglet.window.key.ESCAPE:
        text_entry.focus = False

Custom Widget

class CustomButton(gui.WidgetBase):
    def __init__(self, x, y, width, height, text):
        super().__init__(x, y, width, height)
        self.text = text
        self.pressed = False

        # Create visual elements
        self.bg = pyglet.shapes.Rectangle(
            x, y, width, height,
            color=(100, 100, 200)
        )
        self.label = pyglet.text.Label(
            text,
            x=x + width//2, y=y + height//2,
            anchor_x='center', anchor_y='center'
        )

    def on_mouse_press(self, x, y, button, modifiers):
        if self._check_hit(x, y):
            self.pressed = True
            self.bg.color = (150, 150, 255)
            self.dispatch_event('on_press')

    def on_mouse_release(self, x, y, button, modifiers):
        if self.pressed:
            self.pressed = False
            self.bg.color = (100, 100, 200)

    def _check_hit(self, x, y):
        return (self.x <= x <= self.x + self.width and
                self.y <= y <= self.y + self.height)

CustomButton.register_event_type('on_press')

Common Patterns

Menu System

class Menu:
    def __init__(self, window):
        self.window = window
        self.frame = gui.Frame(window)
        self.batch = pyglet.graphics.Batch()
        self.buttons = []

    def add_button(self, text, callback, y_offset):
        # Create button (simplified)
        button = gui.PushButton(
            x=window.width // 2 - 100,
            y=window.height // 2 + y_offset,
            pressed=pressed_img,
            unpressed=unpressed_img,
            batch=self.batch
        )
        button.callback = callback
        self.frame.add_widget(button)
        self.buttons.append(button)

        @button.event
        def on_press():
            callback()

    def draw(self):
        self.batch.draw()

# Usage
menu = Menu(window)
menu.add_button("Start", lambda: print("Start game"), 50)
menu.add_button("Options", lambda: print("Options"), 0)
menu.add_button("Quit", lambda: pyglet.app.exit(), -50)

Performance Tips

  1. Use batching: Add widgets to a Batch
  2. Frame overhead: Frame uses spatial hashing for efficient hit testing
  3. Disable when hidden: Set enabled=False on hidden widgets
  4. Custom widgets: Inherit from WidgetBase for consistency

Common Issues

  1. Events not firing: Ensure widget added to Frame
  2. Z-order: Later widgets drawn on top
  3. Focus: Only one TextEntry can have focus
  4. Hit testing: Widgets use rectangular bounds
  5. Image requirements: Button needs at least pressed/unpressed images

Install with Tessl CLI

npx tessl i tessl/pypi-pyglet@2.1.1

docs

3d-models.md

app-clock.md

audio-video.md

graphics-rendering.md

gui.md

images-textures.md

index.md

input-devices.md

math.md

opengl.md

resource-management.md

sprites-shapes.md

text-rendering.md

windowing.md

tile.json