Container widgets are able to hold other widgets and take care of
drawing them on their own surface. They are mostly used for layout
purposes or complex widgets, which consist of several other
widgets or which need to add additional functionality to different
widget types (like the ScrolledWindow
widget). They allow to bind one or more widgets as child(ren) to
themselves and take over the role as parent widget.
The abstract Bin class is a container,
that is able to hold exactly one child. It allows to bind und
unbind a child widget and supports setting an additional padding
between its surface borders and the child surface.
You usually will not create a Bin
object directly, but inherit from it in your own widget classes.
The child of a Bin can be set with the
child attribute or
set_child() method. It is not necessary
to register the child at an event manager after binding it to
the Bin as this will set the event
manager of the child to its own one.
label = Label ("Label for a bin")
bin.set_child (label)
# No need to set an event manager explicitly for the label.
bin.manager = eventmanager
For layout purposes the Bin can make use
of additional pixels to place between its outer surface edges
and the child surface. This pixel amount can be modified and
used using the padding attribute of the
Bin. Various inheritors within the
widgets module of OcempGUI make heavy use of this attribute to
adjust the look of themselves. The following example
demonstrates this.
from ocempgui.widgets import Button, Renderer
renderer = Renderer ()
renderer.create_screen (200, 120)
button_5px = Button ("Button with 5px padding")
button_5px.topleft = 5, 5
button_5px.padding = 5
button_10px = Button ("Button with 10px padding")
button_10px.topleft = 5, 60
button_10px.padding = 10
renderer.add_widget (button_5px, button_10px)
renderer.start ()
Example 34. Bin.padding example
The following example provides a complete
Bin implementation which can rotate the
visible of its child (and only the surface).
You can find the following example as a python script under
examples/bin.py.
# Bin examples.
import pygame
from ocempgui.widgets import *
from ocempgui.widgets.Constants import *
class PivotBin (Bin):
"""PivotBin (widget) -> OwnBin
A Bin implementation example class.
This class does not support real rotations of widgets. Instead it
simply rotates their image surface and displays it. Any other
behaviour and information of the widget stay the same. Thus event
capable widgets will not work correctly.
"""
def __init__ (self):
Bin.__init__ (self)
self._orientation = ORIENTATION_HORIZONTAL
def set_orientation (self, orientation=ORIENTATION_HORIZONTAL):
"""P.set_orientation (...) -> None
Sets the orientation of the attached child.
"""
if orientation not in ORIENTATION_TYPES:
raise ValueError("orientation must be a value of ORIENATION_TYPES")
self._orientation = orientation
self.dirty = True
def draw_bg (self):
width, height = self.padding, self.padding
cls = self.__class__
if self.child:
width += self.child.width
height += self.child.height
if self.orientation == ORIENTATION_VERTICAL:
# Swap width and height on demand
width, height = height, width
# Guarantee the set minimum and maximum sizes.
width, height = self.check_sizes (width, height)
surface = base.GlobalStyle.engine.draw_rect (width, height, self.state,
cls, self.style)
return surface
def draw (self):
"""Draws the PivotBin and its child according to the set orientation."""
Bin.draw (self)
if self.child:
rect = self.image.get_rect ()
self.child.center = rect.center
if self.orientation == ORIENTATION_VERTICAL:
# Rotate the child image on demand.
image = pygame.transform.rotate (self.child.image, 90)
rotate_rect = image.get_rect ()
rotate_rect.center = rect.center
self.image.blit (image, rotate_rect)
else:
self.image.blit (self.child.image, self.child.rect)
orientation = property (lambda self: self._orientation,
lambda self, var: self.set_orientation (var),
doc = "The orientation of the child.")
def rotate_bin (bin, button):
# Set the Bin orientation and replace the button.
if bin.orientation == ORIENTATION_HORIZONTAL:
bin.orientation = ORIENTATION_VERTICAL
else:
bin.orientation = ORIENTATION_HORIZONTAL
button.topleft = bin.left, bin.bottom + 10
if __name__ == "__main__":
bin = PivotBin ()
bin.topleft = 10, 10
bin.child = Label ("Simple label in PivotBin")
button = Button ("Switch orientation")
button.topleft = bin.left, bin.bottom
button.connect_signal (SIG_CLICKED, rotate_bin, bin, button)
# Initialize the drawing window.
re = Renderer ()
re.create_screen (300, 300)
re.title = "Bin implementation example"
re.color = (234, 228, 223)
re.add_widget (bin, button)
# Start the main rendering loop.
re.start ()
Example 35. Bin example
The abstract Container widget class is
similar to the Bin class, except that it
can hold more than one widget.
As well as with the Bin, you usually will
not create a Container object directly,
but inherit from it in your own class.
The children can be added using
add_child(), which allows to add
multiple children at once, or
the insert_child() method.
# Add a single child.
container.add_child (label1)
# Add multiple children at once.
container.add_child (label1, button1, label2, entry1)
# Insert a child at a specific position
container.insert_child (1, entry2)
Container
implementation, insert_child() can
cause the inserted child to appear at a specific position.
The removal of children can be done with one widget at a time only
using the remove_child() method of the
Container.
# Only one child can be removed at a time.
container.remove_child (button1)
You also can set the children directly using the
children attribute. The
Container will remove all its children
first and then add the new list of widgets. Simply setting the
children to None will remove all the
widgets of the Container.
# Set a list of widgets as children of a container.
container.children = [label1, button1, entry1]
# Remove all children of the container.
container.children = None
Besides the padding attribute, which was
already explained in the section called “Bin” the
Container has a
spacing attribute, which indicates the
pixel amount to place between its children.
container.spacing = 10
Frame examples in the later section
will show you possible concrete results.
TODO: provide implementation examples
The Box widgets are
Containers which allow an absolute
placement of their attached children. This enables you to let
widgets overlap or place them next o each other according to
your needs while keeping them relative to other widgets without
extensive position calculations. You could e.g. place a
Box into a Frame
so that the contents of the Box are
aligned relative to other widgets of the
Frame while being positioned exactly as
you need.
To create a Box you have to call its
constructor with the size it should occupy.
box = Box (100, 100)
Container methods. The topleft
coordinates of the attached widgets are used to position them
within the Box. Thus a Button with the
topleft value of 10, 10 will be placed 10
pixels from the topleft corner of the Box.
box = Box (100, 100)
button = Button ("A Button")
button.topleft = 10, 10
box.add_child (button)
The Box widget class does not make use
of the padding and
spacing attributes of its
Container parent class. It also does
not resize itself, when a widget leaves its visible area or
occupies more space than the Box.
Below you will find an example to illustrate most of the
abilities of the Box widget
classes. You do not need to care about other widgets like the
VFrame class for now as those are
explained later on.
You can find the following example as a python script under
examples/box.py.
# Box examples.
from ocempgui.widgets import *
from ocempgui.widgets.Constants import *
def create_box_view ():
frame = VFrame (Label ("Box example"))
frame.topleft = 10, 10
# The Box with 200x200 pixels in size.
box = Box (200, 200)
# Widgets to place into it.
label = ImageLabel ("image.png")
label.topleft = 10, 10
button = Button ("A Button")
button.topleft = 30, 30
frame1 = VFrame (Label ("A VFrame"))
frame1.add_child (Label ("Label in the VFrame"))
frame1.topleft = 60, 80
chk = CheckButton ("A CheckButton")
chk.topleft = 130, 110
box.children = label, button, frame1, chk
frame.add_child (box)
return frame
if __name__ == "__main__":
# Initialize the drawing window.
re = Renderer ()
re.create_screen (300, 300)
re.title = "Box examples"
re.color = (234, 228, 223)
re.show_layer_info = True
re.add_widget (create_box_view ())
# Start the main rendering loop.
re.start ()
Example 36. Box example
Frame widgets are
Containers, that support drawing a
decorative border and title widget around their children. The
basic Frame class is an abstract class,
which defines the common attributes and methods for its
inheritors, while the HFrame and
VFrame widgets are concrete
implementations, that place their children horizontally or
vertically. Both subclasses only differ in the placing behaviour
of their widgets and the basic aligning possibilities, so that,
if not stated otherwise, the following examples always apply to
both widget types, although the HFrame is
used.
The creation of a HFrame is done using
frame = HFrame ()
frame = HFrame (widget)
Frame. The title widget can be any valid
BaseWidget subclass and typically be
placed at the topleft corner of the
Frame. If no title widget is supplied, a
complete border will be drawn around the
Frame, while a set title widget will
discontinue that border at the topleft corner. You can change
or set the title widget at any later time. A few possibilities
should be shown here.
frame = HFrame (Label ("A title label"))
frame.widget = Button ("Button as frame title")
frame.set_widget (VFrame (Label ("Frame in a frame")))
To adjust the look of the Frame, it is
possible to change its border style using the
border attribute
frame.border = BORDER_NONE
frame.set_border (BORDER_SUNKEN)
frame.align = ALIGN_TOP
frame.align = ALIGN_LEFT
HFrame and
VFrame has to be made, because each one
only supports a subset of the alignment possibilities. The
HFrame widget natively supports aligning
its children at the top or bottom only
hframe.align = ALIGN_TOP
hframe.set_align (ALIGN_BOTTOM)
VFrame supports only the left
and right alignment.
vframe.align = ALIGN_LEFT
vframe.set_align (ALIGN_RIGHT)
Below you will find an example to illustrate most of the
abilities of the Frame widget
classes. You do not need to care about other widgets like the
Table class for now as those are
explained later on.
You can find the following example as a python script under
examples/frame.py.
# Frame examples.
import os
from ocempgui.widgets import *
from ocempgui.widgets.Constants import *
def create_frame_view ():
table = Table (2, 3)
table.topleft = 5, 5
table.spacing = 5
# Create and display two 'standard' frames.
hframe = HFrame (Label ("Horizontal Frame"))
table.add_child (0, 0, hframe)
lbl = Label ("Vertical Frame" + os.linesep + "with 5 px spacing")
lbl.multiline = True
vframe = VFrame (lbl)
vframe.spacing = 5
table.add_child (0, 1, vframe)
for i in xrange(3):
btn = Button ("Button %d" % i)
hframe.add_child (btn)
btn2 = Button ("Button %d" % i)
vframe.add_child (btn2)
# Create framed frames.
framed1 = VFrame (Label ("VFrame"))
framed2 = HFrame ()
framed3 = VFrame (Label ("VFrame as HFrame.widget"))
framed3.add_child (Label ("Child of a VFrame"))
framed2.widget = framed3
framed2.add_child (Button ("Button 1"), Button ("Button 2"))
button = Button ("Simple Button")
framed1.add_child (framed2, button)
table.add_child (1, 0, framed1)
# Create a Frame with alignment.
frame_align = VFrame (Label ("VFrame with right alignment"))
frame_align.align = ALIGN_RIGHT
label1 = Label ("Label")
label2 = Label ("Even longer label")
button = CheckButton ("A CheckButton")
frame_align.add_child (label1, label2, button)
table.add_child (1, 1, frame_align)
# Add insensitive frames.
hframe = HFrame (Label ("Insensitive HFrame"))
hframe.sensitive = False
table.add_child (0, 2, hframe)
vframe = VFrame (Label ("Insensitive VFrame"))
vframe.sensitive = False
table.add_child (1, 2, vframe)
for i in xrange(3):
btn = Button ("Button %d" % i)
hframe.add_child (btn)
btn2 = Button ("Button %d" % i)
vframe.add_child (btn2)
return table
if __name__ == "__main__":
# Initialize the drawing window.
re = Renderer ()
re.create_screen (600, 300)
re.title = "Frame examples"
re.color = (234, 228, 223)
re.add_widget (create_frame_view ())
# Start the main rendering loop.
re.start ()
Example 37. Frame example
Table widgets, which inherit from the
Container class, allow a table-like
placement of their children in rows and columns. The children
can be placed in the table cells and each cell supports an
individual alignment.
The Table constructor expects the row and
column dimensions to set up for the table, so that
table = Table (2, 2)
table2 = Table (3, 5)
Adding children is different from the usual
Container methods. The
Table needs the additional information,
in which cell to place the child. Thus instead of using
table.add_child (child_widget1, child_widget2) # This does not work!
table.add_child (row, column, child_widget1)
table.add_child (row1, column1, child_widget2)
Table in
contrast works in the same way you already learned about in
the section called “Container”.
Assigning the children attribute of the
Table with a list of widgets adds the
children row for row to it.
As said above, each cell of the Table
supports using an own alignment, which can be set with the
set_align() method.
table.set_align (0, 1, ALIGN_TOP)
table.set_align (1, 1, ALIGN_LEFT)
Table
documentation.
# Aligning the child at the topleft.
table.set_align (0, 1, ALIGN_TOP | ALIGN_LEFT)
# Conflicting alignments, thus using the higher priority of ALIGN_TOP.
table.set_align (0, 1, ALIGN_TOP | ALIGN_BOTTOM)
# Again a conflict. ALIGN_NONE has the lowest priority, thus it will be
# left aligned.
table.set_align (0, 1, ALIGN_LEFT | ALIGN_NONE)
table.set_row_align (row, alignment)
table.set_column_align (column, alignment)
Below you will find an example to illustrate most of the
abilities of the Table widget class.
You can find the following example as a python script under
examples/table.py.
# Table examples.
from ocempgui.widgets import Renderer, Table, Label, Button
from ocempgui.widgets.Constants import *
def create_table_view ():
# Crate and display a Table.
table = Table (9, 2)
table.spacing = 5
table.topleft = 5, 5
label = Label ("Nonaligned wide Label")
table.add_child (0, 0, label)
table.add_child (0, 1, Button ("Simple Button"))
label = Label ("Top align")
table.add_child (1, 0, label)
table.set_align (1, 0, ALIGN_TOP)
table.add_child (1, 1, Button ("Simple Button"))
label = Label ("Bottom align")
table.add_child (2, 0, label)
table.set_align (2, 0, ALIGN_BOTTOM)
table.add_child (2, 1, Button ("Simple Button"))
label = Label ("Left align")
table.add_child (3, 0, label)
table.set_align (3, 0, ALIGN_LEFT)
table.add_child (3, 1, Button ("Simple Button"))
label = Label ("Right align")
table.add_child (4, 0, label)
table.set_align (4, 0, ALIGN_RIGHT)
table.add_child (4, 1, Button ("Simple Button"))
label = Label ("Topleft align")
table.add_child (5, 0, label)
table.set_align (5, 0, ALIGN_TOP | ALIGN_LEFT)
table.add_child (5, 1, Button ("Simple Button"))
label = Label ("Topright align")
table.add_child (6, 0, label)
table.set_align (6, 0, ALIGN_TOP | ALIGN_RIGHT)
table.add_child (6, 1, Button ("Simple Button"))
label = Label ("Bottomleft align")
table.add_child (7, 0, label)
table.set_align (7, 0, ALIGN_BOTTOM |ALIGN_LEFT)
table.add_child (7, 1, Button ("Simple Button"))
label = Label ("Bottomright align")
table.add_child (8, 0, label)
table.set_align (8, 0, ALIGN_BOTTOM |ALIGN_RIGHT)
table.add_child (8, 1, Button ("Simple Button"))
return table
if __name__ == "__main__":
# Initialize the drawing window.
re = Renderer ()
re.create_screen (250, 350)
re.title = "Table examples"
re.color = (234, 228, 223)
re.add_widget (create_table_view ())
# Start the main rendering loop.
re.start ()
Example 38. Table example
ScrolledWindow widgets are
Bin widgets that add scrolling abilities
to their attached child. This is extremely useful for
situations, in which the widget to scroll should not exceed a
specific size, but has to display all of its data. Putting such
a widget in a ScrolledWindow allows you
to respect this specific size, while the widget can grow as it
wants.
You create a ScrolledWindow using
window = ScrolledWindow (width, height)
width and
height denote values for the
size attribute of the
ScrolledWindow. The newly created
ScrolledWindow will not exceed this size
by default.
The widget, which needs to be scrolled is packed into the
ScrolledWindow the usual
Bin way.
window.child = widget_to_scroll
To allow a flexibly scrolling behaviour, you can adjust the
scrolling attribute to make the
ScrolledWindow automatic scrolling,
always scrolling or never scrolling.
window.scrolling = SCROLL_ALWAYS
window.scrolling = SCROLL_NEVER
window.scrolling = SCROLL_AUTO
ScrollBar controls attached to the window
and is described in details in the
set_scrolling() method documentation.
You also can influence the scrollbars of the
ScrolledWindow programmatically.
window.vscrollbar.value = 0
window.hscrollbar.value = window.vscrollbar.maximum
ScrolledWindow to scroll to the topright
of its attached child.
The ScrolledWindow widget natively
listens to two signals to support better navigation
possibilities. Those are
SIG_MOUSEDOWN - Invoked, when a mouse button is pressed down on the ScrolledWindow.
SIG_KEYDOWN - Invoked, when a key gets pressed.
The ScrolledList widget class can be used
to display and manage collections in a list-style look and
feel. Technically it is a ScrolledWindow,
which holdes a ListViewPort that takes
care of displaying the list contents.
As the ScrolledWindow the
ScrolledList supports different scrolling
types and anything else, while the keyboard and mouse behaviour
differ slightly to match the needs of list browsing.
To create a ScrolledList you have to
supply the sizing dimensions and an optional collection, which
makes up the contents.
scrolledlist = ScrolledList (width, height, collection=None)
ListItemCollection (explained later)
object is automatically bound to it. The
ScrolledList however only accepts
collections, which inherit from the
ListItemCollection.
Items can be added and removed dynamically to the list using the items property.
for no in xrange (10):
scrolledlist.items.append (TextListItem ("Item no. %d" % no))
# Last one was too much.
scrolledlist.items.remove (scrolledlist.items[-1])
ListItemCollection wraps a list
and fully supports all important operations of, including
slicing, indexed item access and sorting. More details about the
ListItemCollection can be found in the section called “ListItemCollection”.
The FileList widget is useful to display
filesystem contents in a list-style manner. It supports the
distinction between different filetypes through the
FileListItem item type and allows you to
browse filesystem contents.
As the ScrolledList, from which the
FileList inherits, you need to pass the
size dimensions it should occupy and optionally the initial
starting directory to list the contents of.
filelist = FileList (200, 400, "/usr/home")
FileList will list the contents of the
current directory as set in os.curdir.
It allows to list directories programmatically through the
directory attribute and
set_directory() method.
filelist.directory = "C:\"
filelist.set_directory ("/tmp")
FileList will not
list it, but instead provide an acoustic signal using
print "\a".
The FileList additionally supports the
SIG_DOUBLECLICKED signal to allow changing directories
interactively. Of course own methods can be bound to it.