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.position = 5, 5 button_5px.padding = 5 button_10px = Button ("Button with 10px padding") button_10px.position = 5, 60 button_10px.padding = 10 renderer.add_widget (button_5px, button_10px) renderer.start ()
Example 30. Bin.padding example
TODO: provide implementation examples
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 and removed using the
add_child()
and
remove_child()
methods of the
Container
. In contrast to the
Bin
you cannot add those to the
children attribute directly, which also
should be modified by no means except, that
you know, what you are doing. Doing otherwise can result in an
unwanted misbehaviour of the Container
and GUI.
Adding multiple children at once is possible, while the removal of them can be done with one widget at a time only.
container.add_child (label1, button1, label2, entry1) # Only one child can be removed at a time. container.remove_child (button1)
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
Frame
widgets are
Container
s, 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.position = 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 31. 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”.
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_BOTTOM. 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.position = 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 32. 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.