Search code examples
pythontuiurwid

Urwid horizontal menu - return to previous state or restart loop


I'm building an app based on the Horizontal Menu example from Urwid. I have an item that I want to show some information. I have an "OK" button underneath, and I want it to either pop the menu back to the previous state, or maybe restart the entire screen/loop.

In the example, they use ExitMainLoop(), but I don't want to exit - I just want to restart it. So, I've changed the callback to a different function - but all my attempts either do nothing or crash my program.

Here's the relevant bits:

Starting the menu:

if __name__ == "__main__":
    top = HorizontalBoxes()
    top.open_box(menu_top([]).menu)
    urwid.MainLoop(urwid.Filler(top, 'middle', 40), palette).run()

Relevant menu class/functions. My problem is - what goes in the does_nothing function?

class Choice(urwid.WidgetWrap):
    def __init__(self, caption, pid):
        super(Choice, self).__init__(
            MenuButton(caption, partial(self.item_chosen,pid)))
        self.caption = caption

    def item_chosen(self, pid, button):
        if self.caption == (u"System status"):
            showSystemStatus()


def showSystemStatus():
    response = urwid.Text( "... some text ")
    done = MenuButton(u'OK', does_nothing)
    response_box = urwid.Filler(urwid.Pile([response,done]))
    top.open_box(urwid.AttrMap(response_box, 'options'))

def does_nothing(key):
    ????????????????????
    return

Solution

  • I found a solution! I had to add a new method to the HorizontalBoxes class. Specifically, the close_box method:

    class HorizontalBoxes(urwid.Columns):
        def __init__(self):
            super(HorizontalBoxes, self).__init__([], dividechars=1)
    
        def open_box(self, box):
            if self.contents:
                del self.contents[self.focus_position + 1:]
            self.contents.append((urwid.AttrMap(box, 'options', focus_map),
                self.options('given', 40)))
            self.focus_position = len(self.contents) - 1
    
        def close_box(self):
            if self.contents:
                del self.contents[self.focus_position :]
                self.focus_position = len(self.contents) - 1
    

    And then, it was a simple matter of calling the close_box method from my does_nothing function from before:

    def does_nothing(key):
        top.close_box()
        return