summaryrefslogtreecommitdiff
path: root/docs/tutorial
diff options
context:
space:
mode:
authorIan Ward <ian@excess.org>2012-09-18 14:57:03 -0400
committerIan Ward <ian@excess.org>2012-09-18 14:57:03 -0400
commitc93f671c8d0b3dc1764ead8746da96fa905ab859 (patch)
tree39ef641505a6e942426a3691fe4ef6f5e2a28b9b /docs/tutorial
parent44c5a021d49cdbb98297fb207a057784a207e4c5 (diff)
downloadurwid-c93f671c8d0b3dc1764ead8746da96fa905ab859.tar.gz
tutorial: update edit+button, listbox+listwalker examples
--HG-- branch : feature-sphinx
Diffstat (limited to 'docs/tutorial')
-rw-r--r--docs/tutorial/edit.py19
-rw-r--r--docs/tutorial/frlb.py25
-rw-r--r--docs/tutorial/frlb.py.xdotool4
-rw-r--r--docs/tutorial/frlb1.pngbin416 -> 499 bytes
-rw-r--r--docs/tutorial/frlb2.pngbin651 -> 728 bytes
-rw-r--r--docs/tutorial/frlb3.pngbin765 -> 927 bytes
-rw-r--r--docs/tutorial/frlb4.pngbin850 -> 932 bytes
-rw-r--r--docs/tutorial/index.rst107
-rw-r--r--docs/tutorial/lbcont.py34
-rw-r--r--docs/tutorial/lbcont4.pngbin0 -> 1059 bytes
10 files changed, 90 insertions, 99 deletions
diff --git a/docs/tutorial/edit.py b/docs/tutorial/edit.py
index 3f55507..b7d9817 100644
--- a/docs/tutorial/edit.py
+++ b/docs/tutorial/edit.py
@@ -4,18 +4,15 @@ def exit_on_q(key):
if key in ('q', 'Q'):
raise urwid.ExitMainLoop()
-class Question(urwid.Edit):
- def __init__(self):
- super(Question, self).__init__(u"What is your name?\n")
-
+class QuestionBox(urwid.Filler):
def keypress(self, size, key):
- key = super(Question, self).keypress(size, key)
- if key == 'enter':
- fill.body = urwid.Text(u"Nice to meet you,\n"
- + self.edit_text + u".\n\nPress Q to exit.")
- return None
- return key
+ if key != 'enter':
+ return super(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)
-fill = urwid.Filler(Question())
+edit = urwid.Edit(u"What is your name?\n")
+fill = QuestionBox(edit)
loop = urwid.MainLoop(fill, unhandled_input=exit_on_q)
loop.run()
diff --git a/docs/tutorial/frlb.py b/docs/tutorial/frlb.py
index 6b3a332..c01c1b2 100644
--- a/docs/tutorial/frlb.py
+++ b/docs/tutorial/frlb.py
@@ -1,19 +1,20 @@
import urwid
-def exit_on_cr(key):
- if key == 'enter':
- raise urwid.ExitMainLoop()
-
-def on_ask_change(edit, new_edit_text):
- assert edit is ask # we are passed our edit widget
- reply.set_text(('I say',
- u"Nice to meet you, " + new_edit_text))
-
palette = [('I say', 'default,bold', 'default', 'bold'),]
ask = urwid.Edit(('I say', u"What is your name?\n"))
reply = urwid.Text(u"")
-listbox = urwid.ListBox(urwid.SimpleFocusListWalker([ask, reply]))
+button = urwid.Button(u'Exit')
+div = urwid.Divider()
+pile = urwid.Pile([ask, div, reply, div, button])
+top = urwid.Filler(pile, valign='top')
+
+def on_ask_change(edit, new_edit_text):
+ reply.set_text(('I say', u"Nice to meet you, %s" % new_edit_text))
+
+def on_exit_clicked(button):
+ raise urwid.ExitMainLoop()
+
urwid.connect_signal(ask, 'change', on_ask_change)
+urwid.connect_signal(button, 'click', on_exit_clicked)
-loop = urwid.MainLoop(listbox, palette, unhandled_input=exit_on_cr)
-loop.run()
+urwid.MainLoop(top, palette).run()
diff --git a/docs/tutorial/frlb.py.xdotool b/docs/tutorial/frlb.py.xdotool
index cfde3c4..02a1690 100644
--- a/docs/tutorial/frlb.py.xdotool
+++ b/docs/tutorial/frlb.py.xdotool
@@ -1,4 +1,4 @@
windowsize --usehints $RXVTWINDOWID 21 7
type --window $RXVTWINDOWID 'Tim t'
-type --window $RXVTWINDOWID 'he Ench'
-type --window $RXVTWINDOWID 'anter'
+type --window $RXVTWINDOWID 'he Enchanter'
+key --window $RXVTWINDOWID Down
diff --git a/docs/tutorial/frlb1.png b/docs/tutorial/frlb1.png
index 249d8ec..b5c45be 100644
--- a/docs/tutorial/frlb1.png
+++ b/docs/tutorial/frlb1.png
Binary files differ
diff --git a/docs/tutorial/frlb2.png b/docs/tutorial/frlb2.png
index b0ca366..dfe9526 100644
--- a/docs/tutorial/frlb2.png
+++ b/docs/tutorial/frlb2.png
Binary files differ
diff --git a/docs/tutorial/frlb3.png b/docs/tutorial/frlb3.png
index ea74972..ba3ae36 100644
--- a/docs/tutorial/frlb3.png
+++ b/docs/tutorial/frlb3.png
Binary files differ
diff --git a/docs/tutorial/frlb4.png b/docs/tutorial/frlb4.png
index f120af0..c31405b 100644
--- a/docs/tutorial/frlb4.png
+++ b/docs/tutorial/frlb4.png
Binary files differ
diff --git a/docs/tutorial/index.rst b/docs/tutorial/index.rst
index bc2ace8..1a4c911 100644
--- a/docs/tutorial/index.rst
+++ b/docs/tutorial/index.rst
@@ -183,15 +183,18 @@ 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.
-* ``Question`` is an :class:`Edit` widget that starts with the caption
- ``"What is your name?\n"``. The newline at the end of the caption
- makes the user input start on the next row.
-* ``Question.keypress()`` allows most keystrokes to be handled by
- :meth:`Edit.keypress` so the user to enter their name.
-* When *ENTER* is pressed the Question widget is replaced with
- a :class:`Text` response.
-* When the user presses *Q* after the response is displayed the
- ``exit_on_q`` function will cause the program to exit.
+* In ``QuestionBox.keypress()`` all keypresses except *ENTER* are passed along to
+ the default :meth:`Filler.keypress` which sends them to the
+ child :meth:`Edit.keypress` method.
+* Note that names containing *Q* can be entered into the :class:`Edit`
+ widget without causing the program to exit because :meth:`Edit.keypress`
+ indicates that it has handled the key by returning ``None``.
+ See :meth:`Widget.keypress` for more information.
+* When *ENTER* is pressed the child widget (``original_widget``) is changed
+ to :class:`Text` widget.
+* :class:`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.
.. image:: edit1.png
@@ -199,34 +202,26 @@ and extend than handling all special input in an ``unhandled_input`` function.
.. image:: edit3.png
-Events and ListBox Widget
--------------------------
+Edit and Button Signals
+-----------------------
This program asks for your name and responds "Nice to meet you, (your name)"
-*while* you type your name. *ENTER* exits.
+*while* you type your name. Press *DOWN* then *SPACE* or *ENTER* to exit.
.. literalinclude:: frlb.py
:linenos:
* An :class:`Edit` widget and :class:`Text` reply
widget are created, like in the previous example.
-* A :class:`SimpleListWalker` is then created to manage the
- contents and focus of our :class:`ListBox`. The
- :class:`SimpleListWalker` behaves just like a list of widgets,
- and can be modified like a regular list.
-* A :class:`ListBox` is created and passed the
- :class:`SimpleListWalker`. The :class:`ListBox`
- is a box widget and allows scrolling through its contents. This example is
- simple enough that we could have used a :class:`Pile` widget
- and :class:`Filler` widget instead, but we will see how the
- :class:`ListBox` can be useful in later examples.
* The :func:`connect_signal` function is used to attach our
- :func:`on_ask_change` function to our :class:`Edit` widget's
- *change* event. Now any time the content of the :class:`Edit`
+ ``on_ask_change()`` function to our :class:`Edit` widget's
+ *change* signal. Now any time the content of the :class:`Edit`
widget changes :func:`on_ask_change` will be called and passed the new
content.
-* Now :func:`on_ask_change` updates the reply text as the user enters their
- name.
+* Finally we attach our ``on_exit_clicked()`` function to our
+ exit :class:`Button`'s *click* signal.
+* ``on_ask_change()`` updates the reply text as the user enters their
+ name and ``on_exit_click()`` exits.
.. image:: frlb1.png
.. image:: frlb2.png
@@ -234,8 +229,8 @@ This program asks for your name and responds "Nice to meet you, (your name)"
.. image:: frlb4.png
-Modifying ListBox Content
--------------------------
+ListBox and SimpleFocusListWalker
+---------------------------------
This program asks for your name and responds ``Nice to meet you, (your name).``
It then asks again, and again. Old values may be changed and the responses will
@@ -243,37 +238,39 @@ be updated when you press *ENTER*. *ENTER* on a blank line exits.
.. literalinclude:: lbcont.py
-* When the user presses *ENTER*:
-
- * The widget in focus and its current position is retrieved by calling the
- :meth:`ListBox.get_focus` function.
- * If the widget in focus does not have an :attr:`edit_text` attribute, then
- it is not one of the :class:`Edit` widgets we are interested
- in. One of the :class:`Text` widgets might receive focus if
- it covers the entire visible area of the :class:`ListBox`
- widget and there is no :class:`Edit` widget to take focus.
- While this is unlikely, it should be handled or the program will fail when
- trying to access it.
- * If there is no edit text we exit the program.
- * The widget after the widget in focus (if any exists) is replaced with a
- response.
- * If there is no widget after that widget, a new :class:`Edit`
- widget is created.
- * The focus is then moved to the next :class:`Edit` widget by
- calling :meth:`ListBox.set_focus`.
-
-* All other keys are passed to the top widget to handle. The
- :class:`ListBox` widget does most of the hard work:
-
- * *UP* and *DOWN* will change the focus and/or scroll the widgets in the list
- box.
- * *PAGE UP* and *PAGE DOWN* will try to move the focus one screen up or down.
- * The cursor's column is maintained as best as possible when moving from one
- :class:`Edit` widget to another.
+:class:`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. :ref:`listbox-contents` is managed by
+a "list walker", one of the list walkers that is easiest to use is
+:class:`SimpleFocusListWalker`.
+
+:class:`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 :class:`ListBox`'s keypress handling by overriding
+it in a subclass.
+
+* ``question()`` is used to build widgets to communicate with the user.
+ Here we return a :class:`Pile` widget with a single :class:`Edit` widget
+ to start.
+* We retrieve the name entered with :attr:`ListBox.focus` to get the
+ :class:`Pile` in focus, the standard
+ :ref:`container widget <container-widgets>` method ``[0]`` to get the
+ first child of the pile and :attr:`Edit.edit_text`.
+* For the response we use the fact that we can treat
+ :attr:`Pile.contents` like a list of widgets and options to create or
+ replace any existing response by assigning to ``[1:]``. We assign
+ the new response with the default :meth:`Pile.options`.
+* To add another question after the current one we treat our
+ :class:`SimpleFocusListWalker` like a normal list of widgets and call
+ ``insert()``, then update the focus position to the widget we just
+ created.
.. image:: lbcont1.png
.. image:: lbcont2.png
.. image:: lbcont3.png
+.. image:: lbcont4.png
Menu Example
diff --git a/docs/tutorial/lbcont.py b/docs/tutorial/lbcont.py
index f71d5bb..b2bc8a4 100644
--- a/docs/tutorial/lbcont.py
+++ b/docs/tutorial/lbcont.py
@@ -1,33 +1,29 @@
import urwid
-class Question(urwid.Edit):
- def __init__(self):
- super(Question, self).__init__(('I say', u"What is your name?\n"))
-
- def keypress(self, size, key):
- key = super(Question, self).keypress(size, key)
- if key == 'enter' and not self.edit_text:
- raise urwid.ExitMainLoop()
- return key
+def question():
+ return urwid.Pile([urwid.Edit(('I say', u"What is your name?\n"))])
def answer(name):
return urwid.Text(('I say', u"Nice to meet you, " + name + "\n"))
class ConversationListBox(urwid.ListBox):
def __init__(self):
- super(ConversationListBox, self).__init__(
- urwid.SimpleFocusListWalker([Question()]))
+ body = urwid.SimpleFocusListWalker([question()])
+ super(ConversationListBox, self).__init__(body)
def keypress(self, size, key):
key = super(ConversationListBox, self).keypress(size, key)
- if key != 'enter' or not hasattr(self.focus, 'edit_text'):
+ if key != 'enter':
return key
- # replace or add response below
+ name = self.focus[0].edit_text
+ if not name:
+ raise urwid.ExitMainLoop()
+ # replace or add response
+ self.focus.contents[1:] = [(answer(name), self.focus.options())]
pos = self.focus_position
- self.body[pos + 1:pos + 2] = [answer(self.focus.edit_text)]
- if not self.body[pos + 2:pos + 3]: self.body.append(Question())
- self.set_focus(pos + 2)
+ # add a new question
+ self.body.insert(pos + 1, question())
+ self.focus_position = pos + 1
-palette = [('I say', 'default,bold', 'default', 'bold'),]
-loop = urwid.MainLoop(ConversationListBox(), palette)
-loop.run()
+palette = [('I say', 'default,bold', 'default'),]
+urwid.MainLoop(ConversationListBox(), palette).run()
diff --git a/docs/tutorial/lbcont4.png b/docs/tutorial/lbcont4.png
new file mode 100644
index 0000000..de655ab
--- /dev/null
+++ b/docs/tutorial/lbcont4.png
Binary files differ