Container widgets

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.

Bin

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
        
This however will not be done, if the child is already bound to an event manager.

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

Container

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
        
The Frame examples in the later section will show you possible concrete results.

TODO: provide implementation examples

Frames

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)
        
The difference between both is, that the first constructor does not set up a title widget for the 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)
        
and to change the alignment of its packed children using the align attribute.
frame.align = ALIGN_TOP
frame.align = ALIGN_LEFT
        
Here a diversion between the 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)
        
while the VFrame supports only the left and right alignment.
vframe.align = ALIGN_LEFT
vframe.set_align (ALIGN_RIGHT)
        
Both use no alignment (ALIGN_NONE) by default, which causes their children to be centered relatively to each other.

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

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)
        
would create two tables. The first would be a quadratic one with two rows, of which each serves two columns, which allows to place four children in it, the second sets up three rows with 5 columns in each of it allowing to hold up to fifteen children.

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!
        
you have to add children by identifying the row and column to place them into.
table.add_child (row, column, child_widget1)
table.add_child (row1, column1, child_widget2)
        
Removing children from the 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)
        
Different alignments can be combined, although not any case makes sense and some alignment combinations conflict with each other. Thus the table uses a different aligning priority, which is explained in detail in the 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)
        
Two additional methods allow you to align a complete column or row using a specific alignment value.
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

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)
        
where 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
        
This setting influences the visibility of the both 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
       
The above code would cause the 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.

ScrolledList

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)
        
If the collection is not specified, a basic 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])
        
The bound 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”.

FileList

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")
        
If the initial directory remains unset, the 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")
        
If the user however has not the correct access rights for a specific directory, the 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.