import urwid
palette = [('header', 'white', 'black'),
('reveal focus', 'black', 'dark cyan', 'standout'),]
content = urwid.SimpleListWalker([
urwid.AttrMap(w, None, 'reveal focus') for w in [
urwid.Text("This is a text string that is fairly long"),
urwid.Divider("-"),
urwid.Text("Short one"),
urwid.Text("Another"),
urwid.Divider("-"),
urwid.Text("What could be after this?"),
urwid.Text("The end."),]
])
listbox = urwid.ListBox(content)
show_key = urwid.Text("", 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 == 'enter':
raise urwid.ExitMainLoop()
loop = urwid.MainLoop(top, palette, input_filter=show_all_input, unhandled_input=exit_on_cr)
loop.run()
Pressing up or down should scroll the list but in my case it doesn't. Is there something wrong ?
EDIT 1
Code works perfectly in fact I didn't understand what scrollable lists are. I thought pressing up or down would select item in the list but it doesn't. What this does is just scroll your terminal when it doesn't have enough space to display all items at once. You must resize your terminal to a very small size to understand what this code does.
EDIT 2
To change focus when pressing up or down, a strange API has to be used. I would have loved to see an API like listbox.focus_next()
/ listbox.focus_previous()
, but you have to handle the positions yourself. Of course, you can create your own functions (or subclass ListBox) to offer a better API
def handle_input(input):
if input == "esc":
raise urwid.ExitMainLoop()
head.original_widget.set_text("key pressed: %s" % input)
lw = listbox.body
if input == "up":
# this can raise an error if we scroll past first position
try:
lw.set_focus(lw.get_prev(lw.get_focus()[1])[1])
except:
pass
elif input == "down":
# this can raise an error if we scroll past last position
try:
lw.set_focus(lw.get_next(lw.get_focus()[1])[1])
except:
pass
EDIT 3
A better API :
def urwid_test():
"""
'black', 'dark red', 'dark green', 'brown', 'dark blue',
'dark magenta', 'dark cyan', 'light gray', 'dark gray',
'light red', 'light green', 'yellow', 'light blue',
'light magenta', 'light cyan', 'white'
"""
class MyListBox(urwid.ListBox):
def focus_next(self):
try:
self.body.set_focus(self.body.get_next(self.body.get_focus()[1])[1])
except:
pass
def focus_previous(self):
try:
self.body.set_focus(self.body.get_prev(self.body.get_focus()[1])[1])
except:
pass
def handle_input(input):
if input == "esc":
raise urwid.ExitMainLoop()
head.original_widget.set_text("key pressed: %s" % input)
if input == "up":
listbox.focus_previous()
elif input == "down":
listbox.focus_next()
palette = [("top","white","black"),
("line","light green","dark green","standout"),
("frame","dark magenta","white"),
]
widgets = [urwid.AttrMap(widget,None,"line") for widget in
[
urwid.Text("Chemma!"),
urwid.Divider("-"),
urwid.Text("Another text widget!"),
urwid.Divider("-"),
urwid.Text("What is your name"),
urwid.Divider("-"),
urwid.Text("Boy ?"),
]
]
head = urwid.AttrMap(urwid.Text("key pressed :",wrap="clip"),"top")
L = urwid.SimpleListWalker(widgets)
listbox = MyListBox(L)
top = urwid.AttrMap(urwid.Frame(listbox,head),"frame")
loop = urwid.MainLoop(top,palette,unhandled_input=handle_input)
loop.screen.set_terminal_properties(colors=256)
loop.run()
if __name__ == "__main__":
urwid_test()