Textbasierte GUI mit Perl

Old School

Es muss nicht immer eine Webanwendung sein. Manchmal ist es am einfachsten, ein interaktives Programm für das Textterminal zu schreiben. Auf Komfort muss man dabei nicht unbedingt verzichten.
Wer sein System permanent überwacht, hat den Grundstein dafür gelegt Engpässe zu vermeiden und Fehler frühzeitig zu erkennen. Neben dem Platzhirsch Nagios ... (mehr)

Auch wenn man es sich kaum noch vorstellen kann: Es gibt noch Software, die nicht im Webbrowser läuft. Wer selbst ein kleines Programm schreiben will, um beispielsweise Daten in eine Datenbank einzutragen, kommt auf der Kommandozeile oft schneller voran. Eine vollständige Webanwendung mit Fehlerbehandlung zu schreiben, gerät schneller als man denkt zu einem mittleren Projekt. Da helfen auch keine Frameworks wie Ruby on Rails oder Symfony, die noch dazu einiges an Einarbeitungszeit erfordern.

Curses

Wer dennoch in einem Terminal interaktive Programme schreiben will, greift mit der Programmiersprache C meistens auf die Ncurses-Bibliothek zurück, von der es auch Varianten für Skriptsprachen wie Perl, Python oder Ruby gibt. Besonders komfortabel lassen sich textbasierte "grafische" Oberflächen mit dem Perl-Modul Curses::UI schreiben, das basierend auf Curses klassische GUI-Elemente wie Buttons, Dialoge und Fenster bietet.

Fertige Pakete gibt es für die meisten Linux-Distributionen. Auf Debian und Ubuntu installieren Sie Curses::UI mit »apt-get install libcurses-ui-perl« , Fedora- sowie Red-Hat- und CentOS-Anwender tippen stattdessen »yum install perl-Curses-UI« ein. Auf letzteren Systemen müssen Sie eventuell noch ein Third-Party-Repository wie Repoforge [2] einbinden, wenn das Paket in der Kerndistribution fehlt. Unix-Fans mit Mac OS X können das Perl-Modul beispielsweise mit Macports und »sudo port install p5-curses-ui« installieren.

Um das Modul in eigenen Perl-Skripten zu verwenden, genügt zu Beginn des Skripts die Zeile:

use Curses::UI;

Die folgende Anweisung erzeugt eine Instanz des UI-Objekts, das als Handle für alle weiteren Aktionen dient:

$ui = new Curses::UI( -color_support => 1 );

In farbfähigen Terminals (meist mit ANSI-Farbcodes angesteuert) schaltet der Parameter »-color_support« die Farbunterstützung der Bibliothek ein.

Wie häufig bei GUI-Bibliotheken wird die Benutzeroberfläche hierarchisch aufgebaut. Man hängt also beispielsweise ein Fenster-Element an das UI-Element an. Das Fenster-Element kann als Kinder weitere sogenannte Widgets enthalten, beispielsweise Container als Ordnungselemente zur Gruppierung oder gleich sichtbare Bestandteile wie Buttons oder Auswahllisten.

Ein Fenster beispielsweise fügen Sie so der GUI hinzu und weisen es direkt einer Variablen zu:

$window = $ui->add(
 'window1', 'Window',
 -border => 1,
);

Der erste Parameter gibt eine ID an, über die sich das Fenster später im GUI-Baum wiederfinden lässt, danach folgt der Typ des Widgets, hier eben »Window« . Der Parameter »-border« auf 1 (True) gesetzt, verschafft dem Fenster einen sichtbaren Rand.

Wer die obigen Anweisungen in ein Skript einfügt und ausführt, bekommt eine Fehlermeldung zu sehen, aber auch nicht das gewünschte Ergebnis. Es fehlt nämlich noch der für GUI-Anwendungen typische Event-Loop, in dem das Programm verweilt und Benutzer-Eingaben verarbeitet. Curses::UI bietet dazu die Methode »mainloop()« :

$ui->mainloop();

Bevor Sie das Programm starten, sollten Sie aber noch an den Ausstieg denken, denn mit dem bei Skripten sonst funktionierenden [Strg] + [C] kommen Sie hier nicht weiter. Am besten setzen Sie in jedem Programm eine Tastenzuweisung ein, mit der Sie es beenden können, etwa:

$ui->set_binding( sub{ exit; } , "\cQ");

Das erste Argument der Methode »set_binding« ist eine Referenz auf eine Perl-Funktion, die beim Tastendruck ausgeführt werden soll, etwa »\&myfunction« . Hier ist stattdessen einfach eine anonyme Funktion mit »sub« direkt definiert. Die Tastenkombination, die als zweiter Parameter folgt, entspricht hier [Strg] + [Q] .

Text geben Sie beispielsweise über das UI-Element »Label« aus. Hängen Sie es einfach an das Window-Objekt an und übergeben Sie den Text als Parameter. Die meisten anderen Parameter sind optional und legen unter anderem fest, ob der Text fett oder unterstrichen erscheinen soll:

$window->add(
 'label1', 'Label',
 -text => 'Hier der Text',
);

Ein Label verarbeitet wie alle anderen Elemente auch Standard-Optionen, die es von der Widget-Klasse erbt, von der alle Elemente abgeleitet sind. Dazu gehören unter anderem Breite »-width« und Höhe »-height« sowie die Position innerhalb des umgebenden Containers in Form von X- und Y-Koordinaten, die sich auf die linke obere Ecke des jeweiligen Elements beziehen und die mit »-x« und »-y« angegeben werden.

Leerer Platz innerhalb und außerhalb des Widgets wird mit Padding-Werten angegeben. So legt »-pad« den Wert für alle Achsen fest, »-padright« für die rechte Seite, »-padbottom« für den unteren Rand und so weiter. Analog verhält es sich mit der Innenseite, deren Werte entsprechend »-ipad« , »-ipadright« , »-ipadleft« und so weiter heißen.

Im Dialog

Weil Dialoge zur Interaktion mit dem Anwender recht häufig vorkommen, bietet Curses::UI hierfür eigene Methoden an, und zwar gleich eine ganze Palette davon. Im einfachsten Fall »Dialog::Basic« handelt es sich nur um einen Dialog, den der Anwender mit einem Button bestätigen muss. Mit nur einer Zeile mehr lässt sich so das obige Programm mit einem Abschiedsdialog versehen:

$ui->dialog(-message => 'Goodbye!');

Das komplette Listing mit Fenster, Text und Dialog ist in Abbildung 1 zu sehen. Abbildung 2 zeigt das Resultat.

Abbildung 1: Ein simples Programm mit Curses::UI umfasst nur wenige Zeilen, bietet aber immerhin ein eigenes Fenster und einen Dialog.
Abbildung 2: Curses::UI unterstützt UTF-8 und in modernen Terminalfenstern auch Farben.

Für mehr als eine Antwort, zum Beispiel die klassische Auswahl zwischen OK und Cancel, übergeben Sie als Parameter ein Array mit den gewünschten Buttons, etwa so:

-buttons => ['OK', 'Cancel']

Um herauszufinden, welchen Button der Anwender gedrückt hat, lesen Sie den Return-Wert aus, also » $return = $ui->dialog(...)« .

Manchmal ist es aber nötig, statt einer einfachen Auswahl den Benutzer einen Wert eingeben zu lassen, zum Beispiel einen String oder eine Zahl. Dafür bietet Curses::UI die Klasse »Dialog::Question« . Sie wird folgendermaßen verwendet:

$username = $ui->question('Benutzername:');

An die Antwort gelangt man wieder über den Return-Wert, wie die obige Zeile zeigt. Zur verdeckten Eingabe von Passwörtern gibt es übrigens eine eigene Widget-Klasse namens »Pass-wordEntry« . Neben den einfachen Dialogen bietet Curses::UI auch einen Datei-Browser, einen Progress-Bar und sogar einen Kalender!

Komplexere Daten werden in grafischen Oberflächen meist in Dropdown- oder ähnlichen Listen angezeigt. Auch hier muss das kleine Perl-Modul nicht passen. Mit dem Listbox-Widget lassen sich Listen anzeigen, aus denen der Anwender auswählen kann. Wie bei GUIs und auf HTML-Seiten üblich, erlaubt auch Curses::UI die Funktionen Einfach- oder Mehrfachauswahl. Die ausgewählten Werte übergeben Sie dem Label-Objekt als Array, die optionalen Label als Hash. Ein Beispiel dafür ist in Listing 1 zu sehen. Natürlich könnten Array und Hash die Indizierung auch bei 0 starten.

Listing 1

Label

 

Der Schalter für die Mehrfachauswahl heißt »-multi« , wie in Listing 1 zu sehen ist, die Einfachauswahl legt stattdessen »-radio« fest.

comments powered by Disqus
Einmal pro Woche aktuelle News, kostenlose Artikel und nützliche ADMIN-Tipps.
Ich habe die Datenschutzerklärung gelesen und bin einverstanden.

Konfigurationsmanagement

Ich konfiguriere meine Server

  • von Hand
  • mit eigenen Skripts
  • mit Puppet
  • mit Ansible
  • mit Saltstack
  • mit Chef
  • mit CFengine
  • mit dem Nix-System
  • mit Containern
  • mit anderer Konfigurationsmanagement-Software

Ausgabe /2023