A Little Bit of Widgetry for
This is a framework for creating a GUI using
PyGame. It was developed for use in PyWeek competition entries, and has
been used by the author in several games so far.
Version 1.1 introduced a theme system
to provide a central place for customising the appearance of Albow
widgets, so you can easily give each of your games a distinctive look.
Version 2.0 adds a number of substantial new features, including
TableView widgets and improved TextField-based controls.
Version 2.1 adds drop-down and pop-up menus, music facilities and
Version 2.2 adds Multichoice controls and a number of other
Typical usage of the widget system is as follows:
- Initialize the PyGame display surface.
- Create an instance of RootWidget
or subclass thereof (such as Shell),
passing it the display surface.
- Create additional widgets if needed and add them as
the root widget. If using Shell, create the screens you will be using
and display your main screen.
- Start the frame timer if you will be using it (see RootWidget.set_timer()).
- Call the run()
method of the root widget.
There is a
convention used by the constructors of Widget and its subclasses. As
well as the arguments listed in the documentation for the class's
constructor, you can also pass initial values for any other attributes
of the class as keyword arguments.
You can do this for
attributes of your own Widget subclasses as well, if you pass on any
extra keyword arguments to the base class __init__ method. The only
requirement is that the attribute already exist as an instance or class
attribute, or as a property. This ensures that mistaken keyword
arguments are diagnosed rather than silently creating a new attribute.
provide a centralised way of customising the appearance of Albow
widgets on a per-class basis. There are three parts to the theme
system: theme properties, which are attributes that get looked up
automatically in the currently active themes; the Theme class,
instances of which hold values for the theme properties of a particular
class; and the theme module, which holds a default hierarchy of Theme
instances that your application can replace. See the documentation
pages on each of these for more details.
In addition to the usual PyGame event attributes, some events have
||Time of occurrence of the event, in milliseconds since
pygame.init() was called.
||Position of the mouse in the local coordinate system of
the widget to which it is delivered.
||OpenGL mouse events
||A pair of points representing the projection of the
mouse position onto the near and far clipping planes.
Mouse events are classified into mouse_down, mouse_drag, mouse_up and mouse_move,
and are delivered by calling the corresponding method of the relevant
widget. Mouse-down events are delivered to the widget in which the
event occurs. Mouse-drag and mouse-up events are delivered to the
widget that received the last mouse-down event. Mouse-move events (with
no mouse button pressed) are delivered to the widget in which they
Keyboard events are delivered by calling the key_down or key_up methods
of the widget having the current keyboard
focus. A widget is given the keyboard focus by calling its
method. If the focus widget does not handle a key event, it is
passed up the widget hierarchy until a handler is found.
Both mouse and keyboard events have a set of boolean attributes
indicating the state of the modifier keys at the time of the event:
||True if one of the Shift keys is down.
||True if the Control key is down.
||True if the Alt key (Option key on Macintosh) is down.
||True if the Meta key (Command key on Macintosh, Windows
key on PC keyboards) is down.
either the Control or Meta key is down. This can be used to implement
command keys that work according to either Macintosh or Linux/Windows
Albow also provides timer
events that are delivered to the root widget by calling
method. If you use the Shell and Screen classes, timer events are
dispatched to the currently active Screen. The timer_event() method
returns a boolean indicating whether to update the display.
Albow can be used in an OpenGL environment. To do this, create an
OpenGL display surface (using pygame.display.set_mode()
with OPENGL in the flags) and pass it to the constructor of your root
widget. You can then add widgets derived from GLViewport to provide 3D
drawing areas, as well as ordinary 2D widgets.
There are a few
things to be aware of when mixing 2D and 3D widgets. When using OpenGL,
Albow distinguishes three kinds of widgets:
Container widgets and 3D widgets can have any kind of widget as a
subwidget, but 2D widgets can only contain other 2D widgets.
- 3D widgets -- GLViewport, GLOrtho, GLPerspective and
classes derived from them.
widgets -- most other Albow widgets. These are rendered to a temporary
surface which is then transferred to the screen using glDrawPixels.
widgets -- used for laying out other widgets. By default these are Row,
Column, Grid and classes derived from them. The root widget is also
considered a container widget.
You can turn any 2D widget into a container widget by setting its is_gl_container
property to true. However, when you do this, no drawing is performed
for the widget itself -- its bg_color
properties are ignored, and its draw() method
is never called.
You can also turn a container widget back into an ordinary 2D widget by
setting its is_gl_container
property to false. You might want to do this, for example, to give a Row of buttons
a background or border.
to keep in mind is that drawing on 2D surfaces and transferring them to
an OpenGL window is usually much slower than drawing directly with
OpenGL. So if you want high performance, try to keep the window area
covered by 2D widgets to a minimum.
There are some programs in the demo
directory that exercise many of the classes in the Albow library. You
may find them useful as a source of usage examples.