[Urwid] question : how to display python list using listbox

Ian Ward ian at excess.org
Fri Sep 9 10:57:19 EDT 2011


Nice answer Alain.  I'd like to suggest a small change:

Alain Leufroy wrote on 2011-09-09 04:39:
> from urwid import *
> 
> class SelectableText(Text):
>      """Just a selectable Text widget"""
>      _selectable = True
>      keypress = lambda self, size, key: key
> 
> class BottomWalker(SimpleListWalker):
>      """
>      * manage the specific data
>      * automaticly create a selectable Text for each data set
>      * emit 'focus changed' signal when focus is changed
>      """
>      signals = ['focus changed']

I would replace this:

>      def __init__(self, ids, txts):
>          super(BottomWalker, self).__init__(zip(ids, txts))
>      getvalues = SimpleListWalker.__getitem__
>      def __getitem__(self, focus):
>          return AttrWrap(SelectableText('%s %s' % self.getvalues(focus)), None, 'focus')
>      def set_focus(self, focus):
>          emit_signal(self, 'focus changed', self.getvalues(focus))
>          return super(BottomWalker, self).set_focus(focus)

With this:

     def __init__(self, ids, txts):
         super(BottomWalker, self).__init__([])
         for v in zip(ids, txts):
             w = AttrWrap(SelectableText('%s %s' % v), None, 'focus')
             w._values = v
             self.append(w)
     def set_focus(self, focus):
         emit_signal(self, 'focus changed', self[focus]._values)
         return super(BottomWalker, self).set_focus(focus)


When you recreate widgets every time the list content is requested Urwid
will redraw those widgets every time.  By keeping them around the
caching will work properly.

If you have a case where keeping widget objects around is too much of a
burden on memory, or if you want to lazily create widgets but still want
the caching to work, it should be possible to store weak references to
the widgets.  As long as a widget is on screen Urwid's cache will keep a
reference to it.

Ian

> 
> class Main(Pile):
>      """
>      * display the data at bottom using a list box
>      * display a formated data set at top
>      * automaticly update the top text when focus change at bottom (using signal)
>      """
>      def __init__(self, ids, txts):
>          self.top = Filler(Text(''))
>          self.bottom_walker = BottomWalker(ids, txts)
>          self.bottom = ListBox(self.bottom_walker)
> 
>          contents = [('weight', 0.5, self.top),
>                      ('weight', 0.5, AttrWrap(self.bottom, 'bottom'))]
> 
>          super(Main, self).__init__(contents)
> 
>          connect_signal(self.bottom_walker, 'focus changed', self.update_top)
>          self.bottom_walker.set_focus(0) # force first signal
> 
>      def update_top(self, data):
>          self.top.body.set_text('ID  = %s\nTXT = %s' % data)
> 
> def main():
>      from urwid.raw_display import Screen
>      PALETTE = [('bottom', 'dark red', 'light cyan'),
>                  ('focus', 'light cyan', 'dark red')]
>      mydataID = ['D01','D02','D04','D5']
>      mydataTXT = [
>          'data one',
>          'data two',
>          'data three',
>          'data four',
>          'data five',
>      ]
>      MainLoop(Main(mydataID, mydataTXT), PALETTE, Screen()).run()
> 
> if __name__ == '__main__':
>      main()




More information about the Urwid mailing list