The txtText widget handles formatting blocks of text,
wrapping to the next line when necessary. Widgets like this are called “flow
widgets” because their sizing can have a number of columns given, in this
case the full screen width, then they will flow to fill as many rows as
necessary.

The fillFiller widget fills in blank lines above or
below flow widgets so that they can be displayed in a fixed number of rows.
This Filler will align our Text to the top of the screen, filling all the
rows below with blank lines. Widgets which are given both the number of
columns and number of rows they must be displayed in are called “box
widgets”.

The MainLoop class handles displaying our widgets as
well as accepting input from the user.
The widget passed to MainLoop is called the “topmost” widget.
The topmost widget is used to render the whole screen and so it must be a box widget.
In this case our widgets can’t handle any user input so we need to interrupt
the program to exit with ^C.

The MainLoop class has an optional function
parameter unhandled_input. This function will be called once for each
keypress that is not handled by the widgets being displayed.
Since none of the widgets being displayed here handle input, every key the user
presses will be passed to the show_or_exit function.

The ExitMainLoop exception is used to exit
cleanly from the MainLoop.run() function when the user
presses Q. All other input is displayed by replacing the current Text
widget’s content.

This program displays the string HelloWorld in the center of the screen.
It uses different attributes for the text, the space on either side of the text
and the space above and below the text. It waits for a keypress before exiting.

Display attributes are defined as part of a palette. Valid foreground,
background and
setting values are documented in Foreground and Background Settings
A palette is a list of tuples containing:

Name of the display attribute, typically a string

Foreground color and settings for 16-color (normal) mode

Background color for normal mode

Settings for monochrome mode (optional)

Foreground color and settings for 88 and 256-color modes (optional, see
next example)

Background color for 88 and 256-color modes (optional)

A Text widget is created containing the string "HelloWorld"
with display attribute 'banner'. The attributes of text in a Text widget is
set by using a (attribute, text) tuple instead of a simple text string.
Display attributes will flow with the text, and multiple display attributes may be
specified by combining tuples into a list. This format is called Text Markup.

An AttrMap widget is created to wrap the text
widget with display attribute 'streak'. AttrMap widgets
allow you to map any display attribute to any other display attribute, but by default they
will set the display attribute of everything that does not already have a display attribute.
In this case the text has an attribute, so only the areas around the text
used for alignment will be have the new attribute.

A second AttrMap widget is created to wrap the
Filler widget with attribute 'bg'.

When this program is run you can now clearly see the separation of the text,
the alignment around the text, and the filler above and below the text.

This program displays the string HelloWorld in the center of the screen.
It uses a number of 256-color-mode colors to decorate the text,
and will work in any terminal that supports 256-color mode. It will exit when
Q is pressed.

This palette only defines values for the high color foregroundand
backgrounds, because only the high colors will be used. A real application
should define values for all the modes in their palette. Valid foreground,
background and setting values are documented in Foreground and Background Settings.

This example also demonstrates how you can build the widgets to display
in a top-down order instead of the usual bottom-up order. In some
places we need to use a placeholder widget because we must provide
a widget before the correct one has been created.

Container Widgets like Pile have a
contents property that we can treat like a list of
(widget, options) tuples. Pile.contents supports normal list
operations including append() to add child widgets.
Pile.options() is used to generate the default options
for the new child widgets.

This program asks for your name then responds Nicetomeetyou,(yourname).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

importurwiddefexit_on_q(key):ifkeyin('q','Q'):raiseurwid.ExitMainLoop()classQuestionBox(urwid.Filler):defkeypress(self,size,key):ifkey!='enter':returnsuper(QuestionBox,self).keypress(size,key)self.original_widget=urwid.Text(u"Nice to meet you,\n%s.\n\nPress Q to exit."%edit.edit_text)edit=urwid.Edit(u"What is your name?\n")fill=QuestionBox(edit)loop=urwid.MainLoop(fill,unhandled_input=exit_on_q)loop.run()

The Edit widget is based on the Text widget but it accepts
keyboard input for entering text, making corrections and
moving the cursor around with the HOME, END and arrow keys.

Here we are customizing the Filler decoration widget that is holding
our Edit widget by subclassing it and defining a new keypress()
method. Customizing decoration or container widgets to handle input this way
is a common pattern in Urwid applications. This pattern is easier to maintain
and extend than handling all special input in an unhandled_input function.

Note that names containing Q can be entered into the Edit
widget without causing the program to exit because Edit.keypress()
indicates that it has handled the key by returning None.
See Widget.keypress() for more information.

When ENTER is pressed the child widget original_widget is changed
to a Text widget.

Text widgets don’t handle any keyboard input so all input
ends up in the unhandled_input function exit_on_q, allowing the
user to exit the program.

An Edit widget and a Text reply
widget are created, like in the previous example.

The connect_signal() function is used to attach our
on_ask_change() function to our Edit widget’s
'change' signal. Now any time the content of the Edit
widget changes on_ask_change() will be called and passed the new
content.

This program asks for your name and responds Nicetomeetyou,(yourname).
It then asks again, and again. Old values may be changed and the responses will
be updated when you press ENTER. ENTER on a blank line exits.

ListBox widgets let you scroll through a number of flow widgets
vertically. It handles UP, DOWN, PAGE UP and PAGE DOWN keystrokes
and changing the focus for you. ListBox Contents are managed by
a “list walker”, one of the list walkers that is easiest to use is
SimpleFocusListWalker.

SimpleFocusListWalker is like a normal python list of widgets, but
any time you insert or remove widgets the focus position is updated
automatically.

Here we are customizing our ListBox‘s keypress handling by overriding
it in a subclass.

The question() function is used to build widgets to communicate with the user.
Here we return a Pile widget with a single Edit widget
to start.

For the response we use the fact that we can treat
Pile.contents like a list of (widget, options) tuples to create or
replace any existing response by assigning a one-tuple list to contents[1:]. We create
the default options using Pile.options().

To add another question after the current one we treat our
SimpleFocusListWalker stored as ListBox.body like a normal
list of widgets by calling insert(), then update the focus position to the widget we just
created.

menu() builds a ListBox with a title and a sequence of Button
widgets. Each button has its 'click' signal attached to item_chosen,
with item name is passed as data.
The buttons are decorated with an AttrMap that applies
a display attribute when a button is in focus.

The menu is created and decorated with an Overlay using a
SolidFill as the background. The Overlay is given a
miniumum width and height but is allowed to expand to 60% of the available
space if the user’s terminal window is large enough.

A nested menu effect can be created by having some buttons open new menus. This program
lets you choose an option from a nested menu that cascades across the screen. You may
return to previous menus by pressing ESC.

item_chosen() displays the users’ choice similar to the previous example.

menu_top is the top level menu with all of its child menus and
options built using the functions above.

This example introduces WidgetPlaceholder. WidgetPlaceholder is a
decoration widget that does nothing to the widget it
decorates. It is useful if you need a simple way to replace a widget that doesn’t
involve knowing its position in a container, or in this
case as a base class for a widget that will be replacing its own contents regularly.

CascadingBoxes is a new widget that extends WidgetPlaceholder.
It provides an open_box() method that displays a box widget box “on top of”
all the previous content with an Overlay and a LineBox.
The position of each successive box is shifted right and down from the
previous one.

CascadingBoxes.keypress() intercepts ESC keys to cause the current box
to be removed and the previous one to be shown. This allows the user to
return to a previous menu level.

This example is like the previous but new menus appear on the right and push
old menus off the left side of the screen.
The look of buttons and other menu elements are heavily customized
and new widget classes are used instead of factory functions.

MenuButton is a customized Button widget. Button uses
WidgetWrap to create its appearance and this class replaces the
display widget created by Button by the wrapped widget in
self._w.

SubMenu is implemented with a MenuButton but uses WidgetWrap
to hide the implementation instead of inheriting from MenuButton.
The constructor builds a widget for the menu that this button will open
and stores it in self.menu.

Choice is like SubMenu but displays the item chosen instead of
another menu.

The palette used in this example includes an entry with the special name
None. The foreground and background specified in this entry are used
as a default when no other display attribute is specified.

HorizontalBoxes arranges the menus displayed similar to the previous
example. There is no special handling required for going to previous
menus here because Columns already handles switching focus
when LEFT or RIGHT is pressed. AttrMap with the focus_map
dict is used to change the appearance of a number of the display attributes
when a menu is in focus.

We can use the same sort of code to build a simple adventure game. Instead
of menus we have “places” and instead of submenus and parent menus we just
have “exits”. This example scrolls previous places off the top of the
screen, allowing you to scroll back to view but not interact with previous
places.

This example starts to show some separation between the application logic
and the widgets that have been created. The AdventureGame class is
responsible for all the changes that happen through the game and manages
the topmost widget, but isn’t a widget itself. This is a good pattern to
follow as your application grows larger.