AA_artdeco-haus_sxc1285335_AlePaiva.jpg

© Ale Paiva, sxc.hu

Entwicklung textbasierter Oberflächen, Teil 3

Schlicht, aber schick

Schnell und komfortabel erstellen Sie mit den Python-Bibliotheken für Dialog und Newt Oberflächen für Konsolenprogramme. So erleichtern Sie Eingaben und geben Informationen barrierefrei aus.

Zum Erstellen von textbasierten Interfaces eignen sich neben den klassischen kompilierten Sprachen auch Skriptsprachen, sofern es entsprechende Module gibt. Für Python finden sich eine ganze Reihe Helferlein, von denen zwei schon im ersten Teil des Workshops [1] zur Sprache kamen: das Modul Curses und Urwid. Beide bieten beim Programmieren viel Flexibilität, erfordern aber auch etwas mehr Arbeit.

Pythondialog

Noch etwas komfortabler gerät die Arbeit mit Pythondialog: Es bietet eine ganze Reihe fertiger Dialogboxen an. Als erstes, einfaches Beispiel dient eine Infobox, die jeweils für drei Sekunden im Terminal erscheint und dann wieder verschwindet (Listing 1). In Zeile 6 wird zunächst ein Objekt aus der Klasse Dialog() initialisiert. Über den Parameter dialog="dialog" legen Sie fest, dass Sie alle Aufrufe an die Bibliothek Dialog senden möchten. Hier sind alternative Werte gestattet, zum Beispiel für die grafischen Variante X-dialog [2].

Listing 1

#! /usr/bin/env python
import dialog, time, sys
# Dialogbox initialisieren
d = dialog.Dialog(dialog="dialog")
# Infobox aufrufen
d.infobox("Hello World!")
# 3 sec Pause
time.sleep(3)
# Programm ohne Fehler beenden
sys.exit(0)

Zeile 9 erzeugt eine Infobox, die als Textinformation den String Hello World! erhält. Der Aufruf in Zeile 12 schickt das Programm für drei Sekunden schlafen, so dass Benutzer die Möglichkeit haben, die Dialogbox wahrzunehmen. In Zeile 15 beendet sich das Skript mit dem Rückgabewert 0 – dass heißt, alles lief fehlerfrei.

Um aus der Infobox eine Dialogbox mit einem OK-Knopf zum Bestätigen zu machen, genügt es, in Zeile 9 infobox() durch msgbox() zu ersetzen. Dabei bestimmt das Modul die Größe des Dialogfensters automatisch. Die Breite stellen Sie über den Parameter width ein, maximal die Breite des Terminalfensters.

Für Ja-Nein-Fragen nutzen Sie die Yesno-Box (Listing 2). Betätigt der Anwender den mit Ja bezeichneten Knopf, liefert der Funktionsaufruf den Wert DIALOG_OK zurück. Daneben gibt es die Rückgabewerte DIALOG_CANCEL (Abbrechen), DIALOG_ESC (Escape-Taste zum Abbrechen des Dialogs), DIALOG_ERROR (Fehler), DIALOG_EXTRA und DIALOG_HELP (für mögliche Hilfeknöpfe).

Listing 2

# -*- coding: utf-8 -*-
# ! /usr/bin/env python
import dialog, time, sys
# Dialogbox initialisieren
d = dialog.Dialog(dialog="dialog")
# Nachrichtenbox aufrufen
antwort = d.yesno("Neues USB-Gerät gefunden: A380. Einbinden?")
# Antwort auswerten
if antwort == d.DIALOG_OK:
  d.msgbox("Yippieh, los geht's :-)")
else:
  d.msgbox("Feigling :-p")
# Programm ohne Fehler beenden
sys.exit(0)

TIPP

In Listing 2 steht in der ersten Zeile ein Hinweis auf das Encoding des Python-Codes. UTF-8 klingt erst einmal unnütz, da Python es ohnehin als Standardwert für das Encoding nutzt. Es ist aber wichtig zur Ansteuern von dialog, damit dieses korrekt mit den Umlauten und Sonderzeichen aus dem Programmquelltext umgeht.

Als Möglichkeiten für Auswahlfelder stehen Menüs, Check- und Radio-Boxen bereit. In den Zeilen 13 bis 18 (Listing 3) erfolgt die Definition des Auswahlmenüs. Zeile 14 legt die Überschrift fest, die über dem Auswahlmenü erscheint. Die Variable width in Zeile 15 bestimmt, wie breit das Fenster der Auswahl erscheint – längere Einträge schneidet die Software ab. Die einzelnen Auswahlpunkte des Menüs geben die Zeilen 16 bis 18 an. Dabei besteht jeder Eintrag aus einem Index und einer Beschreibung.

Listing 3

# -*- coding: utf-8 -*-
#! /usr/bin/env python
import dialog, time, sys
# Dialogbox initialisieren
d = dialog.Dialog(dialog="dialog")
# Menubox erzeugen
while 1:
  (code, tag) = d.menu(
    "Wohin geht die Reise?",
    width=60,
    choices=[("Amsterdam", "Stadt der Kanäle und Grachten"),
             ("Berlin", "In die beste Stadt der Welt"),
             ("Cannes", "Filme und Meer")])
  if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
    break
  if code == d.DIALOG_OK:
    d.msgbox("Ihre Auswahl: " + tag)
    break
# Programm ohne Fehler beenden
sys.exit(0)

Als Rückgabe erhalten Sie aus dem Aufruf des Menüs (Abbildung 1) ein Tupel aus zwei Werten zurück – dem Tastencode (code) und dem ausgewählten Menüpunkt (tag). Mit [Esc] oder der Auswahl der Schaltfläche Abbrechen brechen Sie die Auswahl und damit das Programm ab (Zeilen 20 bis 21). Mit [Eingabe] wählen Sie einen Menüpunkt aus; die Auswahl erscheint nachfolgend in einer Messagebox (Zeilen 23 bis 25).

Abbildung 1: Die Menüauswahl mit Pythondialog liefert als Rückgabewert den gewählte Punkt.

Checkbox und Radiobox ähneln der Menüauswahl – der Aufruf erfolgt fast identisch. Der Unterschied liegt darin, wie Sie die einzelnen Menüpunkte festlegen. Es gilt einen zusätzlichen Parameter anzugeben, der entweder den Wert 0 oder 1 hat. 0 signalisiert, dass ein Punkt nicht ausgewählt ist, 1 bedeutet hingegen ausgewählt. Bei der Checkbox (Abbildung 2) darf der Benutzer mehrere Menüpunkte auswählen, bei der Radiobox nur einen einzelnen. Das Ergebnis der Auswahl landet in der Variable tag, die bei der Checkbox aus einer Liste besteht, bei der Radiobox wiederum nur aus einem Einzelwert.

Abbildung 2: Über eine Checkbox mit Pythondialog fragen Sie auf einfache Weise Werte ab.

Newt

Newt spielt in der gleichen Liga wie Pythondialog – es bringt bereits viele fertige Elemente mit. Dazu zählen Fenster, Knöpfe und Auswahlfelder. Im Vergleich zu Pythondialog wirkt Newt einfacher und schlanker, was sich aber in der Praxis nicht als Nachteil erweist.

Newt setzt jedoch ein wenig mehr Arbeit voraus als Pythondialog. Nach dem Importieren des Moduls snack gilt es, zunächst einen Rahmen zum Ansprechen, zum Sichern und Wiederherstellen des aktuellen Bildschirminhalts bereitzustellen (Listing 4).

Listing 4

from snack import *
class gb:
  scrn = None
def initScreen():
  gb.scrn = SnackScreen()
  return
def restoreScreen():
  gb.scrn.finish()
  return

Die lokal definierte Klasse gb fasst alle Variablen zusammen, die das Programm global benötigt. Das ist kein Muss, erleichtert aber im Beispiel den Zugriff. Die Variable gb.scrn dient dazu, Operationen auf dem Bildschirm auszuführen – zum Beispiel Fenster zu erzeugen, darzustellen und wieder zu entfernen.

Die Funktion initScreen() sichert den aktuellen Bildschirminhalt, restoreScreen() stellt ihn später wieder. Beide Funktionen braucht das Programm vor und nach einem Aufruf für ein Dialogfenster. Eine Auswahlbox (ListboxChoiceWindow) für eine Fahrtzielauswahl (Abbildung 3) erstellen Sie damit ganz leicht (Listing 5).

Listing 5

destination = ('Helgoland', 'Trier', 'Bautzen', 'Friedrichshafen')
listboxSelection = 0
initScreen()
lbcw = ListboxChoiceWindow(
  gb.scrn,
  'Auswahlmenu',
  'Ein Fahrtziel festlegen:',
  destination,
  default = listboxSelection,
  help = 'Hilfe?',
  buttons = ('OK', 'Beenden')
)
restoreScreen()
listboxButton = lbcw[0]
listboxSelection = lbcw[1]
if listboxButton == 'ok':
  print "Fahrtziel: %s" % destination[listboxSelection]
Abbildung 3: Eine einfach Auswahlbox haben Sie mit Python/Newt in wenigen Minuten programmiert.

Zeile 1 definiert die einzelnen Fahrtziele (destination) als Liste, Zeile 2 setzt die Vorauswahl auf den ersten Eintrag in dieser Liste. Da das Zählen der Indizes in Python bei Null beginnt, reicht im vorliegenden Fall der der Wertebereich von 0 bis 3 (vier Einträge). Der Aufruf der Funktion initScreen() in Zeile 4 bereitet den Bildschirm entsprechend vor.

Die Zeilen 6 bis 14 erzeugen die Auswahlbox. Newt stellt dazu die Funktion ListboxChoiceWindow() bereit, die die folgenden Parameter benötigt:

  • Zeile 7: das Fensterobjekt zum Darstellen aller Elemente
  • Zeile 8: der Fenstertitel
  • Zeile 9: die Beschreibung zur Auswahl
  • Zeile 10: die Auswahlmöglichkeiten (hier: die Fahrtziele)
  • Zeile 11: die Vorauswahl in der Auswahlliste
  • Zeile 12: der angezeigte Hilfetext
  • Zeile 13: die Knöpfe, über die das Fenster verfügt. Hier sind es zwei – OK und Beenden. Für weitere Schaltflächen ergänzen Sie die Liste nach Bedarf.

Zeile 14 enthält die schließende Klammer zum Funktionsaufruf in Zeile 6. Zeile 16 dient als Gegenstück zu Zeile 4, wobei diese den Bildschirminhalt in den Zustand vor dem Aufruf der Auswahlbox versetzt. Die nachfolgenden Zeilen werten das Ergebnis der Auswahlbox aus. Dieses liegt als Liste mit zwei Elementen vor: Der erste Eintrag enthält den betätigten Knopf, der zweite Eintrag den Index in der Auswahlliste.

Zeile 20 prüft, ob der Anwender den Knopf OK gedrückt hat. Falls ja, gibt das Skript das gewünschte Fahrtziel aus (Zeile 21). Es spielt beim Auswerten keine Rolle, ob Sie den Knopf mit Groß- oder Kleinbuchstaben beschriften – die Funktion ListboxChoiceWindow() gibt in jedem Fall den Text in Kleinbuchstaben zurück.

Als weiteres Beispiel (Listing 6) dient der Eingabedialog für ein kleines Adressbuch, das aus dem Projekt Nanowawi [3] stammt (Abbildung 4). Die Zeilen 2 bis 11 definieren die Eingabefelder und deren Bezeichner für das Adressbuch. Zeile 13 legt die Breite des Fensters auf 70 Zeichen fest; Zeile 14 bestimmt für die Eingabefelder eine Breite von 50 Zeichen. Das Fenster benötigt zwei Knöpfe – OK und Cancel – diese definiert Zeile 15. Die Zeilen 16 und 17 bestimmen den Titel und die Textinformation des Fensters.

Abbildung 4: Nur wenige Zeilen Code reichen aus, um eine Eingabemaske zu erstellen.

Listing 6

# list of entry fields
entryFields = [
  ('Title', ''),
  ('First Name', ''),
  ('Last Name', ''),
  ('Street', ''),
  ('City', ''),
  ('ZIP Code', ''),
  ('Region', ''),
  ('Country', '')
]
windowWidth = 70
entryFieldLength = 50
buttons = ['OK', 'Cancel']
windowTitle = 'Address Fields for customer 2'
windowMessage = 'Currently, the following information is stored:'
# init newt screen
initScreen()
returnValue = EntryWindow(
  gb.scrn,
  windowTitle,
  windowMessage,
  entryFields,
  1,
  windowWidth,
  entryFieldLength,
  buttons,
  None)
# restore old screen
restoreScreen()

Das Initialisieren des Fensters geschieht in Zeile 19, der eigentliche Aufruf des Fensters in den Zeilen 22 bis 31. Zeile 34 stellt den Fensterzustand vor dem Aufruf wieder her. Um zu erfahren, wie der Benutzer das Eingabefenster verließ, wertet das Skript zum Abschluss die Variable returnValue aus. Sie besteht aus einem Feld mit zwei Einträgen, der erste für den gedrückten Knopf und der zweite mit einer Liste der Eingabewerte (Listing 7).

Listing 7

returnButton = returnValue[0]
returnFields = returnValue[1]
if returnButton == 'ok':
  description = ["Titel", "Vorname", "Name", "Strasse", "Ort", "PLZ", "Region", "Land"]
  index = 0
  for item in description:
    print "%s: %s" % (item, returnFields[index])
    index = index + 1

LinuxCommunity kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Entwicklung textbasierter Oberflächen, Teil 2
    Textbasierte Benutzeroberflächen zu erstellen, ist nicht besonders kompliziert. Die vorgestellten Frameworks erfordern zwar zunächst etwas Einarbeitungszeit, ermöglichen aber sehr viel Freiheit beim Design.
  • Textbasierte User-Interfaces (Teil 1)
    Die Kommandozeile halten viele Anwender für trist und schlecht bedienbar. Das muss aber nicht so sein: Mithilfe von Dialog und Whiptail werten Sie Ihre eigenen Skripts unkompliziert mit Fenstern, Menüs und Dialogen auf.
  • Mehr Komfort
    Von einfachen Abfragen bis hin zu komplexen Menüs: Mit dem Toolkit Dialog bauen Sie eine grafische Oberfläche für Shell-Skripte, die oft nicht mehr als eine zusätzliche Zeile brauchen.
  • Anwendungen
    Kaum ein halbes Jahr auf dem Markt, bietet die Mathematik-Software Maple in Version 8 nicht nur die neue "Maplet"-Technologie als Standardpaket, sondern zeigt auch, dass sie sich nicht nur an Mathematiker wendet. Während Fachzeitschriften reihenweise die neuen mathematischen Funktionen auflisten, wollen wir hier aufzeigen, was sich hinter Maplets verbirgt und was alles im Internet auf die verschiedenen Anwender wartet.
  • KDE Themes Teil 3
    Dass KDE die Fähigkeit besitzt, recht schnell mittels sogenannter Themes sein Äußeres zu ändern, dürfte inzwischen hinreichend bekannt sein. Diese Serie beschreibt, wie man eigene Themes erstellt.
Kommentare

Infos zur Publikation

LU 12/2016: Neue Desktops

Digitale Ausgabe: Preis € 5,99
(inkl. 19% MwSt.)

LinuxUser erscheint monatlich und kostet 5,95 Euro (mit DVD 8,50 Euro). Weitere Infos zum Heft finden Sie auf der Homepage.

Das Jahresabo kostet ab 86,70 Euro. Details dazu finden Sie im Computec-Shop. Im Probeabo erhalten Sie zudem drei Ausgaben zum reduzierten Preis.

Bei Google Play finden Sie digitale Ausgaben für Tablet & Smartphone.

HINWEIS ZU PAYPAL: Die Zahlung ist ohne eigenes Paypal-Konto ganz einfach per Kreditkarte oder Lastschrift möglich!

Aktuelle Fragen

Drucker Epson XP-332 unter ubuntu 14.04 einrichten
Andrea Wagenblast, 30.11.2016 22:07, 2 Antworten
Hallo, habe vergeblich versucht mein Multifunktionsgerät Epson XP-332 als neuen Drucker unter...
Apricity Gnome unter Win 10 via VirtualBox
André Driesel, 30.11.2016 06:28, 2 Antworten
Halo Leute, ich versuche hier schon seit mehreren Tagen Apricity OS Gnome via VirtualBox zum l...
EYE of Gnome
FRank Schubert, 15.11.2016 20:06, 2 Antworten
Hallo, EOG öffnet Fotos nur in der Größenordnung 4000 × 3000 Pixel. Größere Fotos werden nic...
Kamera mit Notebook koppeln
Karl Spiegel, 12.11.2016 15:02, 2 Antworten
Hi, Fotografen ich werde eine SONY alpha 77ii bekommen, und möchte die LifeView-Möglichkeit nu...
Linux auf externe SSD installieren
Roland Seidl, 28.10.2016 20:44, 1 Antworten
Bin mit einem Mac unterwegs. Mac Mini 2012 i7. Würde gerne Linux parallel betreiben. Aber auf e...