In order to let pyglet process operating system events such as mouse and keyboard events, applications need to enter an application event loop. The event loop continuously checks for new events, dispatches those events, and updates the contents of all open windows.
pyglet provides an application event loop that is tuned for performance and low power usage on Windows, Linux and Mac OS X. Most applications need only call:
pyglet.app.run()
to enter the event loop after creating their initial set of windows and
attaching event handlers. The run()
function does not return until all open
windows have been closed, or until pyglet.app.exit()
is called.
The pyglet application event loop dispatches window events (such as for mouse
and keyboard input) as they occur and dispatches the
on_draw()
event to
each window after every iteration through the loop.
To have additional code run periodically or every iteration through the loop, schedule functions on the clock (see Calling functions periodically). pyglet ensures that the loop iterates only as often as necessary to fulfill all scheduled functions and user input.
The pyglet event loop is encapsulated in the
EventLoop
class, which provides
several hooks that can be overridden for customising its behaviour. This is
recommended only for advanced users – typical applications and games are
unlikely to require this functionality.
To use the EventLoop
class directly, instantiate it and call run:
event_loop = pyglet.app.EventLoop()
event_loop.run()
Only one EventLoop
can be running at a time; when the
run()
method is called
the module variable pyglet.app.event_loop
is set to the running instance.
Other pyglet modules such as pyglet.window
depend on this.
You can listen for several events on the event loop instance. The most useful
of these is on_window_close()
, which is dispatched whenever a window is
closed. The default handler for this event exits the event loop if there are
no more windows. The following example overrides this behaviour to exit the
application whenever any window is closed:
event_loop = pyglet.app.EventLoop()
@event_loop.event
def on_window_close(window):
event_loop.exit()
return pyglet.event.EVENT_HANDLED
event_loop.run()
The pyglet.app.EventLoop.idle()
method is called every iteration of the event loop. It
is responsible for calling scheduled clock functions, redrawing windows, and
deciding how idle the application is. You can override this method if you
have specific requirements for tuning the performance of your application;
especially if it uses many windows.
The default implementation has the following algorithm:
Call pyglet.clock.tick()
with poll=True
to call any scheduled functions.
Dispatch the on_draw()
event and call
flip()
on every open window.
Return the value of pyglet.clock.get_sleep_time()
.
The return value of the get_sleep_time()
method is the number of seconds
until the event loop needs to iterate again (unless there is an earlier user-input event);
or None
if the loop can wait for input indefinitely.
Note that this default policy causes every window to be redrawn during every user event – if you have more knowledge about which events have an effect on which windows you can improve on the performance of this method.
Earlier versions of pyglet and certain other windowing toolkits such as PyGame
and SDL require the application developer to write their own event loop. This is
usually just an inconvenience compared to pyglet.app.run()
, but can be
necessary in some situations when combining pyglet with other toolkits.
A simple event loop usually has the following form:
while True:
pyglet.clock.tick()
for window in pyglet.app.windows:
window.switch_to()
window.dispatch_events()
window.dispatch_event('on_draw')
window.flip()
The dispatch_events()
method checks the window’s operating system
event queue for user input and dispatches any events found. The method does not wait for
input – if ther are no events pending, control is returned to the program immediately.
The call to pyglet.clock.tick()
is required for ensuring scheduled functions
are called, including the internal data pump functions for playing sounds, animations, and
video.
While it is possible to write your own event loop in this way, it is strongly discouraged for the following reasons:
The EventLoop
class provides plenty of hooks for most toolkits to be
integrated without needing to resort to a manual event loop.
Because EventLoop
is tuned for specific operating systems, it is more
responsive to user events, and continues calling clock functions while
windows are being resized, and (on Mac OS X) the menu bar is being tracked.
It is difficult to write a manual event loop that does not consume 100% CPU while still remaining responsive to user input.
The capability for writing manual event loops remains for legacy support and extreme cases where the developer knows what they are doing.