Curses-Programmierung mit Python¶
Was ist curses?¶
Die curses-Bibliothek bietet für textbasierte Terminals eine terminalunabhängige Einrichtung zum Zeichnen des Bildschirms und zum Verarbeiten der Tastatur. Zu solchen Terminals gehören VT100-Geräte, die Linux-Konsole und das nachgebildete Terminal, das verschiedene Programme bereitstellen. Anzeigeterminals unterstützen verschiedene Steuercodes für verbreitete Vorgänge wie das Bewegen des Cursors, das Rollen des Bildschirms und das Löschen von Bereichen. Unterschiedliche Terminals verwenden stark voneinander abweichende Codes und haben oft ihre eigenen kleinen Eigenheiten.
In einer Welt grafischer Anzeigen könnte man fragen: „Warum die Mühe?“ Es ist wahr, dass Terminals mit Zeichenzellen eine überholte Technik sind, aber es gibt Nischen, in denen es noch wertvoll ist, ausgefeilte Dinge mit ihnen tun zu können. Eine Nische sind kleine oder eingebettete Unix-Systeme, auf denen kein X-Server läuft. Eine andere sind Werkzeuge wie Betriebssysteminstallationsprogramme und Kernel-Konfiguratoren, die möglicherweise laufen müssen, bevor überhaupt grafische Unterstützung verfügbar ist.
Die curses-Bibliothek bietet recht grundlegende Funktionalität: Sie gibt dem Programmierer die Abstraktion einer Anzeige, die mehrere sich nicht überlappende Textfenster enthält. Der Inhalt eines Fensters lässt sich auf verschiedene Weisen ändern – Text hinzufügen, löschen, sein Erscheinungsbild ändern – und die curses-Bibliothek findet heraus, welche Steuercodes an das Terminal gesendet werden müssen, um die richtige Ausgabe zu erzeugen. curses bietet nicht viele Konzepte für Benutzeroberflächen wie Schaltflächen, Kontrollkästchen oder Dialoge, wenn du solche Funktionen brauchst, erwäge eine Bibliothek für Benutzeroberflächen wie Urwid.
Die curses-Bibliothek wurde ursprünglich für BSD Unix geschrieben. Die späteren System-V-Versionen von Unix von AT&T ergänzten viele Verbesserungen und neue Funktionen. BSD-curses wird nicht mehr gepflegt und wurde durch ncurses ersetzt, eine Open-Source-Umsetzung der AT&T-Schnittstelle. Wenn du ein Open-Source-Unix wie Linux oder FreeBSD verwendest, nutzt dein System so gut wie sicher ncurses. Da die meisten heutigen kommerziellen Unix-Versionen auf System-V-Code beruhen, werden alle hier beschriebenen Funktionen wahrscheinlich verfügbar sein. Die älteren curses-Versionen, die manche proprietären Unix-Systeme mitbringen, unterstützen allerdings möglicherweise nicht alles.
Die Windows-Fassung von Python enthält das Modul curses nicht. Das Paket windows-curses von Dritten bietet dieselbe Schnittstelle unter Windows.
Das Python-Modul curses¶
Das Python-Modul ist eine recht einfache Hülle um die C-Funktionen, die curses bereitstellt, wenn du mit curses-Programmierung in C schon vertraut bist, lässt sich dieses Wissen wirklich leicht auf Python übertragen. Der größte Unterschied ist, dass die Python-Schnittstelle die Dinge vereinfacht, indem sie verschiedene C-Funktionen wie addstr(), mvaddstr() und mvwaddstr() zu einer einzigen Methode addstr() zusammenfasst. Das wird später ausführlicher behandelt.
Dieses HOWTO ist eine Einführung in das Schreiben von Textmodus-Programmen mit curses und Python. Es versucht nicht, eine vollständige Anleitung zur curses-API zu sein. Dafür lies den Abschnitt zu ncurses in der Anleitung zur Python-Bibliothek und die C-Handbuchseiten zu ncurses. Es gibt dir aber die grundlegenden Ideen mit.
Eine curses-Anwendung starten und beenden¶
Bevor irgendetwas geschieht, muss curses initialisiert werden. Das geschieht durch den Aufruf der Funktion initscr(), die den Terminaltyp bestimmt, alle nötigen Einrichtungscodes an das Terminal sendet und verschiedene interne Datenstrukturen anlegt. Bei Erfolg gibt initscr() ein Fensterobjekt zurück, das den gesamten Bildschirm darstellt. Es wird üblicherweise stdscr genannt, nach dem Namen der entsprechenden C-Variablen.
import curses
stdscr = curses.initscr()
Üblicherweise schalten curses-Anwendungen das automatische Anzeigen der Tastenanschläge auf dem Bildschirm ab, um Tasten lesen und sie nur unter bestimmten Umständen anzeigen zu können. Dazu ist ein Aufruf der Funktion noecho() nötig.
curses.noecho()
Häufig müssen Anwendungen außerdem unmittelbar auf Tasten reagieren, ohne dass die Eingabetaste gedrückt werden muss. Das heißt cbreak-Modus, im Gegensatz zum üblichen gepufferten Eingabemodus.
curses.cbreak()
Terminals geben besondere Tasten – etwa die Cursortasten oder Navigationstasten wie Bild auf und Pos1 – üblicherweise als Mehrbyte-Escape-Sequenz zurück. Du könntest deine Anwendung so schreiben, dass sie solche Sequenzen erwartet und entsprechend verarbeitet, aber curses kann das für dich tun und einen besonderen Wert wie curses.KEY_LEFT zurückgeben. Damit curses diese Arbeit übernimmt, musst du den keypad-Modus einschalten.
stdscr.keypad(True)
Eine curses-Anwendung zu beenden ist viel leichter, als sie zu starten. Du musst Folgendes aufrufen:
curses.nocbreak()
stdscr.keypad(False)
curses.echo()
um die curses-freundlichen Terminaleinstellungen rückgängig zu machen. Rufe dann die Funktion endwin() auf, um das Terminal in seine ursprüngliche Betriebsart zurückzuversetzen.
curses.endwin()
Ein verbreitetes Problem beim Debuggen einer curses-Anwendung ist, dass dein Terminal durcheinandergerät, wenn die Anwendung stirbt, ohne das Terminal in seinen früheren Zustand zurückzuversetzen. In Python passiert das häufig, wenn dein Code fehlerhaft ist und eine nicht gefangene Ausnahme auslöst. Tastenanschläge werden dann zum Beispiel nicht mehr auf dem Bildschirm angezeigt, was die Arbeit mit der Shell erschwert.
In Python kannst du diese Komplikationen vermeiden und das Debuggen deutlich erleichtern, indem du die Funktion curses.wrapper() importierst und so verwendest:
from curses import wrapper
def main(stdscr):
# Clear screen
stdscr.clear()
# This raises ZeroDivisionError when i == 10.
for i in range(0, 11):
v = i-10
stdscr.addstr(i, 0, '10 divided by {} is {}'.format(v, 10/v))
stdscr.refresh()
stdscr.getkey()
wrapper(main)
Die Funktion wrapper() nimmt ein aufrufbares Objekt und führt die oben beschriebenen Initialisierungen durch. Sie initialisiert auch die Farben, wenn Farbunterstützung vorhanden ist. wrapper() führt dann das von dir übergebene aufrufbare Objekt aus. Sobald es zurückkehrt, versetzt wrapper() das Terminal in seinen ursprünglichen Zustand zurück. Das aufrufbare Objekt wird innerhalb eines try…except aufgerufen, das Ausnahmen fängt, den Zustand des Terminals wiederherstellt und die Ausnahme dann erneut auslöst. Dein Terminal bleibt bei einer Ausnahme also nicht in einem komischen Zustand zurück, und du kannst die Meldung der Ausnahme und den Traceback lesen.
Fenster und Pads¶
Fenster sind die grundlegende Abstraktion in curses. Ein Fensterobjekt stellt einen rechteckigen Bereich des Bildschirms dar und unterstützt Methoden, um Text anzuzeigen, ihn zu löschen, den Benutzer Zeichenketten eingeben zu lassen und so weiter.
Das Objekt stdscr, das die Funktion initscr() zurückgibt, ist ein Fensterobjekt, das den gesamten Bildschirm abdeckt. Viele Programme brauchen nur dieses einzige Fenster, aber du möchtest den Bildschirm vielleicht in kleinere Fenster teilen, um sie getrennt neu zu zeichnen oder zu leeren. Die Funktion newwin() erzeugt ein neues Fenster gegebener Größe und gibt das neue Fensterobjekt zurück.
begin_x = 20; begin_y = 7
height = 5; width = 40
win = curses.newwin(height, width, begin_y, begin_x)
Beachte, dass das in curses verwendete Koordinatensystem ungewöhnlich ist. Koordinaten werden immer in der Reihenfolge y,x übergeben, und die linke obere Ecke eines Fensters ist die Koordinate (0,0). Das bricht die übliche Konvention für Koordinaten, bei der die x-Koordinate zuerst kommt. Das ist ein unglücklicher Unterschied zu den meisten anderen Computeranwendungen, aber es gehört zu curses, seit es zum ersten Mal geschrieben wurde, und es ist zu spät, daran noch etwas zu ändern.
Deine Anwendung kann die Größe des Bildschirms über die Variablen curses.LINES und curses.COLS bestimmen, um die y- und x-Größe zu bekommen. Zulässige Koordinaten reichen dann von (0,0) bis (curses.LINES - 1, curses.COLS - 1).
Wenn du eine Methode aufrufst, um Text anzuzeigen oder zu löschen, erscheint die Wirkung nicht sofort auf der Anzeige. Du musst stattdessen die Methode refresh() der Fensterobjekte aufrufen, um den Bildschirm zu aktualisieren.
Der Grund: curses wurde ursprünglich mit Blick auf langsame Terminalverbindungen mit 300 Baud geschrieben. Bei diesen Terminals war es sehr wichtig, die Zeit zum Neuzeichnen des Bildschirms gering zu halten. curses sammelt die Änderungen am Bildschirm stattdessen und zeigt sie auf die effizienteste Weise an, wenn du refresh() aufrufst. Wenn dein Programm zum Beispiel etwas Text in einem Fenster anzeigt und das Fenster dann leert, muss der ursprüngliche Text nicht gesendet werden, weil er nie sichtbar ist.
In der Praxis verkompliziert es die Programmierung mit curses nicht wirklich sehr, curses ausdrücklich zum Neuzeichnen eines Fensters aufzufordern. Die meisten Programme stürzen sich in eine Flut von Tätigkeiten und halten dann an, um auf einen Tastenanschlag oder eine andere Handlung des Benutzers zu warten. Du musst nur sicherstellen, dass der Bildschirm neu gezeichnet wurde, bevor du zum Warten auf Benutzereingaben anhältst – indem du zuvor stdscr.refresh() oder die Methode refresh() eines anderen betroffenen Fensters aufrufst.
Ein Pad ist ein Sonderfall eines Fensters. Es kann größer sein als der tatsächliche Anzeigebildschirm, und es wird jeweils nur ein Teil des Pads angezeigt. Zum Erzeugen eines Pads sind Höhe und Breite des Pads nötig, während beim Aktualisieren eines Pads die Koordinaten des Bildschirmbereichs angegeben werden müssen, in dem ein Teilbereich des Pads angezeigt wird.
pad = curses.newpad(100, 100)
# These loops fill the pad with letters; addch() is
# explained in the next section
for y in range(0, 99):
for x in range(0, 99):
pad.addch(y,x, ord('a') + (x*x+y*y) % 26)
# Displays a section of the pad in the middle of the screen.
# (0,0) : coordinate of upper-left corner of pad area to display.
# (5,5) : coordinate of upper-left corner of window area to be filled
# with pad content.
# (20, 75) : coordinate of lower-right corner of window area to be
# : filled with pad content.
pad.refresh( 0,0, 5,5, 20,75)
Der Aufruf von refresh() zeigt einen Teilbereich des Pads in dem Rechteck an, das sich auf dem Bildschirm von Koordinate (5,5) bis Koordinate (20,75) erstreckt. Die linke obere Ecke des angezeigten Teilbereichs ist die Koordinate (0,0) auf dem Pad. Abgesehen von diesem Unterschied sind Pads genau wie gewöhnliche Fenster und unterstützen dieselben Methoden.
Wenn du mehrere Fenster und Pads auf dem Bildschirm hast, gibt es einen effizienteren Weg, den Bildschirm zu aktualisieren und das störende Flimmern zu verhindern, das beim Aktualisieren jedes Bildschirmteils entsteht. refresh() tut nämlich zwei Dinge:
Es ruft die Methode
noutrefresh()jedes Fensters auf, um eine darunterliegende Datenstruktur zu aktualisieren, die den gewünschten Zustand des Bildschirms darstellt.Es ruft die Funktion
doupdate()auf, um den tatsächlichen Bildschirm an den gewünschten Zustand anzupassen, der in der Datenstruktur festgehalten ist.
Du kannst stattdessen noutrefresh() für eine Reihe von Fenstern aufrufen, um die Datenstruktur zu aktualisieren, und dann doupdate(), um den Bildschirm zu aktualisieren.
Text anzeigen¶
Aus der Sicht eines C-Programmierers kann curses manchmal wie ein verwundenes Labyrinth von Funktionen aussehen, die alle feine Unterschiede haben. So zeigt zum Beispiel addstr() eine Zeichenkette an der aktuellen Cursorposition im Fenster stdscr an, während mvaddstr() zuerst zu einer gegebenen y,x-Koordinate springt, bevor es die Zeichenkette anzeigt. waddstr() ist genau wie addstr(), erlaubt aber die Angabe eines Fensters anstelle der Vorgabe stdscr. mvwaddstr() erlaubt die Angabe von Fenster und Koordinate.
Zum Glück verbirgt die Python-Schnittstelle all diese Details. stdscr ist ein Fensterobjekt wie jedes andere, und Methoden wie addstr() nehmen mehrere Argumentformen an. Üblicherweise gibt es vier verschiedene Formen.
Form |
Beschreibung |
|---|---|
str or ch |
Zeigt die Zeichenkette str oder das Zeichen ch an der aktuellen Position an |
str or ch, attr |
Zeigt die Zeichenkette str oder das Zeichen ch mit dem Attribut attr an der aktuellen Position an |
y, x, str or ch |
Springt zur Position y,x innerhalb des Fensters und zeigt str oder ch an |
y, x, str or ch, attr |
Springt zur Position y,x innerhalb des Fensters und zeigt str oder ch mit dem Attribut attr an |
Attribute erlauben es, Text in hervorgehobenen Formen anzuzeigen, etwa fett, unterstrichen, invertiert oder in Farbe. Sie werden im nächsten Unterabschnitt ausführlicher erklärt.
Die Methode addstr() nimmt als anzuzeigenden Wert eine Python-Zeichenkette oder eine Bytefolge. Der Inhalt von Bytefolgen wird unverändert an das Terminal gesendet. In einem Build ohne Unterstützung für breite Zeichen werden Zeichenketten mit dem Wert des Attributs encoding des Fensters kodiert. Dieses entspricht standardmäßig der Standardkodierung des Systems, wie sie locale.getencoding() zurückgibt.
Die Methoden addch() nehmen ein Zeichen, das entweder eine Zeichenkette der Länge 1, eine Bytefolge der Länge 1 oder eine Ganzzahl sein kann.
Für die Zeichen des alternativen Zeichensatzes des Terminals gibt es Konstanten. So ist zum Beispiel ACS_PLMINUS ein Plus-Minus-Zeichen und ACS_ULCORNER die linke obere Ecke eines Kastens (praktisch zum Zeichnen von Rahmen). Du kannst auch das passende Unicode-Zeichen verwenden.
Fenster merken sich, wo der Cursor nach der letzten Operation stehen geblieben ist. Lässt du die Koordinaten y,x weg, wird die Zeichenkette oder das Zeichen also dort angezeigt, wo die letzte Operation endete. Du kannst den Cursor auch mit der Methode move(y,x) bewegen. Weil manche Terminals immer einen blinkenden Cursor anzeigen, solltest du dafür sorgen, dass der Cursor an einer Stelle steht, an der er nicht ablenkt. Es kann verwirren, wenn der Cursor an einer scheinbar zufälligen Stelle blinkt.
Wenn deine Anwendung überhaupt keinen blinkenden Cursor braucht, kannst du curs_set(False) aufrufen, um ihn unsichtbar zu machen. Die Fenstermethode leaveok() tut etwas anderes: Ist ihr Argument wahr, lässt curses den Cursor dort, wo die letzte Aktualisierung ihn hingesetzt hat, anstatt ihn zurück auf die Cursorposition des Fensters zu bewegen.
Attribute und Farbe¶
Zeichen lassen sich auf verschiedene Weisen anzeigen. Statuszeilen in einer textbasierten Anwendung werden häufig invertiert dargestellt, oder ein Textbetrachter muss bestimmte Wörter hervorheben. curses unterstützt das, indem du für jede Zelle des Bildschirms ein Attribut angeben kannst.
Ein Attribut ist eine Ganzzahl, wobei jedes Bit für ein anderes Attribut steht. Du kannst versuchen, Text mit mehreren gesetzten Attributbits anzuzeigen, aber curses sichert nicht zu, dass alle möglichen Kombinationen verfügbar oder visuell voneinander unterscheidbar sind. Das hängt von den Fähigkeiten des verwendeten Terminals ab. Am sichersten bleibst du daher bei den am häufigsten verfügbaren Attributen, die hier aufgeführt sind.
Attribut |
Beschreibung |
|---|---|
Blinkender Text |
|
Besonders heller oder fetter Text |
|
Halbheller Text |
|
Invertierter Text |
|
Die beste verfügbare Hervorhebungsart |
|
Unterstrichener Text |
Um also eine invertierte Statuszeile in der obersten Zeile des Bildschirms anzuzeigen, könntest du Folgendes schreiben:
stdscr.addstr(0, 0, "Current mode: Typing mode",
curses.A_REVERSE)
stdscr.refresh()
Die curses-Bibliothek unterstützt auf den Terminals, die das anbieten, außerdem Farbe. Das verbreitetste solche Terminal ist wahrscheinlich die Linux-Konsole, gefolgt von farbfähigen xterms.
Um Farbe zu verwenden, musst du kurz nach dem Aufruf von initscr() die Funktion start_color() aufrufen, um den Standardfarbsatz zu initialisieren (die Funktion curses.wrapper() tut das automatisch). Ist das erledigt, gibt die Funktion has_colors() TRUE zurück, wenn das verwendete Terminal tatsächlich Farbe anzeigen kann. (Beachte: curses verwendet die amerikanische Schreibweise „color“ anstelle der kanadisch-britischen Schreibweise „colour“. Wenn du an die britische Schreibweise gewöhnt bist, musst du dich für diese Funktionen damit abfinden, sie falsch zu schreiben.)
Die curses-Bibliothek führt eine begrenzte Anzahl von Farbpaaren, die jeweils eine Vordergrundfarbe (oder Textfarbe) und eine Hintergrundfarbe enthalten. Den Attributwert, der zu einem Farbpaar gehört, bekommst du mit der Funktion color_pair(). Dieser lässt sich bitweise mit anderen Attributen wie A_REVERSE ODER-verknüpfen, aber auch hier ist nicht zugesichert, dass solche Kombinationen auf allen Terminals funktionieren.
Ein Beispiel, das eine Textzeile mit dem Farbpaar 1 anzeigt:
stdscr.addstr("Pretty text", curses.color_pair(1))
stdscr.refresh()
Wie gesagt besteht ein Farbpaar aus einer Vordergrund- und einer Hintergrundfarbe. Die Funktion init_pair(n, f, b) ändert die Definition des Farbpaars n auf die Vordergrundfarbe f und die Hintergrundfarbe b. Das Farbpaar 0 ist fest auf Weiß auf Schwarz verdrahtet und lässt sich nicht ändern.
Farben sind durchnummeriert, und start_color() initialisiert beim Einschalten des Farbmodus 8 Grundfarben. Es sind: 0: Schwarz, 1: Rot, 2: Grün, 3: Gelb, 4: Blau, 5: Magenta, 6: Cyan und 7: Weiß. Das Modul curses definiert für jede dieser Farben eine benannte Konstante: curses.COLOR_BLACK, curses.COLOR_RED und so weiter.
Fügen wir das alles zusammen. Um die Farbe 1 auf roten Text auf weißem Hintergrund zu ändern, würdest du Folgendes aufrufen:
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
Wenn du ein Farbpaar änderst, wechselt aller bereits mit diesem Farbpaar angezeigte Text auf die neuen Farben. Du kannst neuen Text in dieser Farbe auch so anzeigen:
stdscr.addstr(0,0, "RED ALERT!", curses.color_pair(1))
Sehr ausgefeilte Terminals können die Definitionen der tatsächlichen Farben auf einen gegebenen RGB-Wert ändern. Damit kannst du die Farbe 1, die üblicherweise Rot ist, auf Violett, Blau oder jede andere Farbe ändern, die du magst. Leider unterstützt die Linux-Konsole das nicht, ich kann es daher nicht ausprobieren und keine Beispiele geben. Ob dein Terminal das kann, prüfst du mit einem Aufruf von can_change_color(), das True zurückgibt, wenn die Fähigkeit vorhanden ist. Wenn du das Glück hast, ein so begabtes Terminal zu besitzen, findest du weitere Informationen in den Handbuchseiten deines Systems.
Benutzereingaben¶
Die C-Bibliothek curses bietet nur sehr einfache Eingabemechanismen. Das Python-Modul curses ergänzt ein grundlegendes Bedienelement zur Texteingabe. (Andere Bibliotheken wie Urwid haben umfangreichere Sammlungen von Bedienelementen.)
Es gibt drei Methoden, um Eingaben aus einem Fenster zu bekommen:
get_wch()aktualisiert den Bildschirm und wartet dann darauf, dass der Benutzer eine Taste drückt. Die Taste wird angezeigt, wennecho()vorher aufgerufen wurde. Du kannst wahlweise eine Koordinate angeben, zu der der Cursor vor dem Anhalten bewegt werden soll.getch()tut dasselbe, gibt aber anstelle eines Zeichens den Code der Taste zurück. Bei ncurses ist das ein einzelnes Byte der Kodierung der Taste im aktuellen Gebietsschema. Ein Zeichen, das mit mehreren Bytes kodiert ist, braucht daher mehrere Aufrufe, ein Byte je Aufruf.getkey()tut dasselbe wiegetch(), gibt aber eine Zeichenkette zurück: eine gewöhnliche Taste als Zeichenkette mit einem Zeichen und eine besondere Taste als ihren Namen, etwaKEY_UP.
Mit der Fenstermethode nodelay() ist es möglich, nicht auf den Benutzer zu warten. Nach nodelay(True) blockieren die Lesevorgänge für das Fenster nicht mehr. Um anzuzeigen, dass keine Eingabe bereitsteht, löst get_wch() und getkey() eine Ausnahme aus, und getch() gibt -1 zurück. Es gibt außerdem eine Funktion halfdelay(), mit der sich (im Ergebnis) für jeden Lesevorgang ein Zeitgeber setzen lässt. Steht innerhalb einer angegebenen Verzögerung (in Zehntelsekunden) keine Eingabe bereit, scheitert der Lesevorgang auf dieselbe Weise.
Besondere Tasten wie Bild auf, Pos1 oder die Cursortasten werden von allen drei Methoden als eine der KEY_*-Konstanten zurückgegeben, die alle größer als 255 sind. Du kannst den zurückgegebenen Wert mit Konstanten wie curses.KEY_PPAGE, curses.KEY_HOME oder curses.KEY_LEFT vergleichen. Die Hauptschleife deines Programms kann etwa so aussehen:
while True:
c = stdscr.get_wch()
if c == 'p':
PrintDocument()
elif c == 'q':
break # Exit the while loop
elif c == curses.KEY_HOME:
x = y = 0
Das Modul curses.ascii stellt Funktionen bereit, die die Zugehörigkeit zu ASCII-Klassen prüfen und entweder ganzzahlige Argumente oder Zeichenketten mit einem Zeichen annehmen. Die können nützlich sein, um lesbarere Prüfungen für solche Schleifen zu schreiben. Es stellt außerdem Umwandlungsfunktionen bereit, die entweder ganzzahlige Argumente oder Zeichenketten mit einem Zeichen annehmen und denselben Typ zurückgeben. So gibt zum Beispiel curses.ascii.ctrl() das Steuerzeichen zurück, das zu seinem Argument gehört.
Es gibt außerdem eine Methode, um eine ganze Zeile abzurufen: getstr(). Sie wird nicht sehr oft verwendet, weil ihre Funktionalität recht begrenzt ist. Die einzigen verfügbaren Bearbeitungstasten sind das Lösch- und das Kill-Zeichen sowie die Eingabetaste, die die Zeile beendet. Sie gibt ein bytes-Objekt zurück und lässt sich wahlweise auf eine feste Anzahl von Bytes begrenzen.
curses.echo() # Enable echoing of characters
# Get a line of at most 15 bytes, with the cursor on the top line
s = stdscr.getstr(0,0, 15)
Das Modul curses.textpad stellt ein Textfeld bereit, das einen Emacs-artigen Satz von Tastenbelegungen unterstützt. Verschiedene Methoden der Klasse Textbox unterstützen das Bearbeiten mit Eingabeprüfung und das Einsammeln der Bearbeitungsergebnisse – mit oder ohne angehängte Leerzeichen. Hier ein Beispiel:
import curses
from curses.textpad import Textbox, rectangle
def main(stdscr):
stdscr.addstr(0, 0, "Enter IM message: (hit Ctrl-G to send)")
editwin = curses.newwin(5,30, 2,1)
rectangle(stdscr, 1,0, 1+5+1, 1+30+1)
stdscr.refresh()
box = Textbox(editwin)
# Let the user edit until Ctrl-G is struck.
box.edit()
# Get resulting contents
message = box.gather()
Näheres steht in der Bibliotheksdokumentation zu curses.textpad.
Weitere Informationen¶
Dieses HOWTO behandelt einige fortgeschrittene Themen nicht, etwa das Lesen des Bildschirminhalts oder das Erfassen von Mausereignissen aus einer xterm-Instanz, aber die Bibliotheksseite zum Modul curses ist inzwischen recht vollständig. Die solltest du als Nächstes durchsehen.
Wenn du über das genaue Verhalten der curses-Funktionen im Zweifel bist, lies die Handbuchseiten deiner curses-Umsetzung, ob ncurses oder die eines proprietären Unix-Anbieters. Die Handbuchseiten dokumentieren alle Eigenheiten und geben vollständige Listen aller Funktionen, Attribute und ACS_*-Zeichen, die dir zur Verfügung stehen.
Weil die curses-API so groß ist, werden manche Funktionen in der Python-Schnittstelle nicht unterstützt. Oft liegt das nicht daran, dass sie schwer umzusetzen wären, sondern daran, dass sie bisher niemand gebraucht hat. Außerdem unterstützt Python die Menü-Bibliothek, die zu ncurses gehört, noch nicht. Patches, die Unterstützung dafür ergänzen, sind willkommen. Wie du Patches bei Python einreichst, erfährst du im Python Developer’s Guide.
Writing Programs with NCURSES: ein ausführliches Tutorial für C-Programmierer.
„Use curses… don’t swear“: Video eines Vortrags von der PyCon 2013 über die Steuerung von Terminals mit curses oder Urwid.
„Console Applications with Urwid“: Video eines Vortrags von der PyCon CA 2012, der einige mit Urwid geschriebene Anwendungen vorführt.