pythonurwid

How to update content of SimpleWalkerList in Urwid?


I cant find a proper way to update the content of the SimpleWalkerList in URWID. Below is simplified example of the code I am trying to generate list base on the user input:

    import urwid

palette = [('header', 'white', 'black'),
    ('reveal focus', 'black', 'dark cyan', 'standout')]

items = [urwid.Text("foo"),
         urwid.Text("bar"),
         urwid.Text("baz")]

content = urwid.SimpleListWalker([
    urwid.AttrMap(w, None, 'reveal focus') for w in items])

listbox = urwid.ListBox(content)

show_key = urwid.Text("Press any key", wrap='clip')
head = urwid.AttrMap(show_key, 'header')
top = urwid.Frame(listbox, head)

def show_all_input(input, raw):

    show_key.set_text("Pressed: " + " ".join([
        unicode(i) for i in input]))
    return input


def exit_on_cr(input):
    if input in ('q', 'Q'):
        raise urwid.ExitMainLoop()
    elif input == 'up':
        focus_widget, idx = listbox.get_focus()
        if idx > 0:
            idx = idx-1
            listbox.set_focus(idx)
    elif input == 'down':
        focus_widget, idx = listbox.get_focus()
        idx = idx+1
        listbox.set_focus(idx)
    elif input == 'enter':
        pass
    # 
    #how here can I change value of the items list  and display the ne value????
    #
def out(s):
    show_key.set_text(str(s))


loop = urwid.MainLoop(top, palette,
    input_filter=show_all_input, unhandled_input=exit_on_cr)
loop.run()

Expected result would be changing the value for example from 'foo' to 'oof' (so simple string manipulation). Whatever way I am using is not allowing me to manipulate on the values. Do I need to brake the loop and redraw the entire screen from scratch?

Thanks in advance!


Solution

  • As explained in the docs for SimpleListWalker:

    contents – list to copy into this object

    Changes made to this object (when it is treated as a list) are detected automatically and will cause ListBox objects using this list walker to be updated.

    So, all you have to do is modify the elements in the list:

    elif input in 'rR':
        _, idx = listbox.get_focus()
        am = content[idx].original_widget
        am.set_text(am.text[::-1])
    

    Even if you had immutable values in the list, you could just replace them with new objects:

    elif input in 'rR':
        _, idx = listbox.get_focus()
        w = urwid.Text(content[idx].original_widget.text[::-1])
        content[idx] = urwid.AttrMap(w, None, 'reveal focus')
    

    But since you don't have any immutable objects getting in the way, that isn't necessary; the first version will work fine.

    Either way, if you press r, whatever text you were pointing at gets reversed, like foo to oof. (Of course if you were using any markup, you'd need to do something a bit more careful than that, but you're not.)