Simpler Dialog mit urwid

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Habe mich nun mal ein wenig in die urwid-Bibliothek eingearbeitet. Herausgekommen ist ein kleines Modul zum Erzeugen von sehr einfachen Dialogen mit wahlweise einem oder zwei Buttons. Das Design ist noch extrem billig, aber ich habe schon in Beispielen gesehen, dass mehr möglich ist, wenn eigene Farb-Paletten übergeben werden. Die Buttons verstehen sich immerhin inklusive Callbacks für die Rückgabewerte, an die ich dann über ein try-except-Konstrukt herankomme. So, und hier der Code:

Code: Alles auswählen

#!/usr/bin/env python3
import urwid

class ButtonPressed(Exception):
    def __init__(self, state):
        self.state = state

    def __str__(self):
        return str(self.state)

def button_exit(button, state):
    raise ButtonPressed(state)

def get_buttons(labels_to_action):
    buttons = [
        urwid.Button(label, func, state)
        for label, (func, state) in labels_to_action.items()
    ]
    width = max(map(len, labels_to_action)) + 4
    return urwid.GridFlow(
        buttons, width, 3, 1, "center"
    )

def get_message_box(message, title="", confirm="OK", reject=None):
    text = urwid.Text(message, "center")
    button_actions = {confirm: (button_exit, True)}
    if reject:
        button_actions[reject] = (button_exit, False)
    buttons = get_buttons(button_actions)
    widgets = [urwid.Divider(), text, urwid.Divider(), buttons]
    return urwid.LineBox(urwid.Pile(widgets), title)

def run_loop(box):
    screen_widget = urwid.Filler(
        urwid.Padding(box, "center", ("relative", 50))
    )
    urwid.MainLoop(screen_widget).run()

def main():
    box = get_message_box(
        "Geht das nicht noch etwas schöner?",
        title="Frage", confirm="Ja", reject="Nein"
    )
    try:
        run_loop(box)
    except ButtonPressed as result:
        print(result)

if __name__ == "__main__":
    main()
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snafu: Rückgabewerte über Ausnahmen, die ja extra erfunden wurden um besondere Ereignisse von normalen Rückgabewerten zu trennen, finde ich ein bisschen schräg als API.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Mit etwas Farbe sieht es gleich viel ansprechender aus:

Code: Alles auswählen

#!/usr/bin/env python3
import urwid

PALETTE = [
    ("box", "black", "light gray"),
    ("fill-area", "black", "light blue"),
    ("button", "black", "dark cyan"),
    ("button-focus", "white", "dark blue")
]

class ButtonPressed(Exception):
    def __init__(self, state):
        self.state = state

    def __str__(self):
        return str(self.state)


def button_exit(button, state):
    raise ButtonPressed(state)


def get_buttons(labels_to_action):
    buttons = [
        urwid.AttrMap(
            urwid.Button(label, func, state), "button", "button-focus"
        )
        for label, (func, state) in labels_to_action.items()
    ]
    width = max(map(len, labels_to_action)) + 4
    return urwid.GridFlow(buttons, width, 3, 1, "center")

def get_message_box(message, title="", confirm="OK", reject=None):
    text = urwid.Text(message, "center")
    button_actions = {confirm: (button_exit, True)}
    if reject:
        button_actions[reject] = (button_exit, False)
    buttons = get_buttons(button_actions)
    widgets = [urwid.Divider(), text, urwid.Divider(), buttons]
    message_box = urwid.LineBox(urwid.Pile(widgets), title)
    return urwid.AttrMap(message_box, "box")

def run_loop(box, palette=[]):
    padding = urwid.Padding(box, "center", ("relative", 50))
    screen_widget = urwid.AttrMap(urwid.Filler(padding), "fill-area")
    urwid.MainLoop(screen_widget, palette).run()

def main():
    box = get_message_box(
        "Geht das nicht noch etwas schöner?",
        title="Frage", confirm="Ja", reject="Nein"
    )
    try:
        run_loop(box, PALETTE)
    except ButtonPressed as result:
        print(result)

if __name__ == "__main__":
    main()
Das Verwenden von Exceptions zur Flusssteuerung habe ich schon an anderen Stellen gesehen. Irgendwie muss der Rückgabewert ja zum Anwender gelangen, wenn nicht per print() ins Terminal geschrieben werden soll. Gibt es denn dafür eine andere Möglichkeit, außer dass man das Programm objektorientiert umschreibt?
Antworten