Python: urwid: trying to handle different views
Question: I try to program with different views.

Therefor, i tried to make a class which handles different views with urwid,
also to separate the view code from the rest.

After a lot of different tries i don't know where to start anymore.

Which urwid objects do i need for a clean erasing and redraw of the screen,
and how do they need to be encapsulated so i can switch views after user
input?


Answer: From the [Urwid documentation](http://urwid.org/manual/mainloop.html#widgets-
displayed):

> The topmost widget displayed by MainLoop must be passed as the first
> parameter to the constructor. **If you want to change the topmost widget
> while running, you can assign a new widget to the MainLoop object’s
> MainLoop.widget attribute. This is useful for applications that have a
> number of different modes or views.**

Now for some code:

    
    
    import urwid
    
    # This function handles input not handled by widgets.
    # It's passed into the MainLoop constructor at the bottom.
    def unhandled_input(key):
      if key in ('q','Q'):
        raise urwid.ExitMainLoop()
      if key == 'enter':
        try:
    
          ## This is the part you're probably asking about
    
          loop.widget = views.next().build()   
        except StopIteration:
          raise urwid.ExitMainLoop()
    
    # A class that is used to create new views, which are 
    # two text widgets, piled, and made into a box widget with
    # urwid filler
    class MainView(object):
      def __init__(self,title_text,body_text):
        self.title_text = title_text
        self.body_text = body_text
    
      def build(self):
        title = urwid.Text(self.title_text)
        body = urwid.Text(self.body_text)
        body = urwid.Pile([title,body])
        fill = urwid.Filler(body)
        return fill
    
    # An iterator consisting of 3 instantiated MainView objects.
    # When a user presses Enter, since that particular key sequence
    # isn't handled by a widget, it gets passed into unhandled_input.
    views = iter([ MainView(title_text='Page One',body_text='Lorem ipsum dolor sit amet...'),
              MainView(title_text='Page Two',body_text='consectetur adipiscing elit.'),
              MainView(title_text='Page Three',body_text='Etiam id hendrerit neque.')
            ])
    
    initial_view = views.next().build()
    loop = urwid.MainLoop(initial_view,unhandled_input=unhandled_input)
    loop.run()
    

In short, I've used a global key handling function to listen for a certain
sequence pressed by the user and on receiving that sequence, my key handling
function builds a new view object with the MainView class and replaces
`loop.widget` with that object. Of course, in an actual application, you're
going to want to create a signal handler on a particular widget in your view
class rather than use the global unhandled_input function for all user input.
You can read about the connect_signal function
[here](http://urwid.org/reference/signals.html?highlight=closure#signal-
functions).

Note the part about garbage collection in Signal Functions documentation: if
you're intending to write something with many views, they will remain in
memory even after you've replaced them due to the fact that the signal_handler
is a closure, which retains a reference to that widget implicitly, so you need
to pass the `weak_args` named argument into the `urwid.connect_signal`
function to tell Urwid to let it go once its not actively being used in the
event loop.

