Laut dem offiziellen Dokument
Die curses-Bibliothek bietet terminalunabhängige Bildschirmzeichnung und Tastaturverarbeitung für textbasierte Terminals (Terminals) wie VT100s, Linux-Konsolen und Emulationsterminals, die von verschiedenen Programmen bereitgestellt werden. Das Terminal unterstützt verschiedene Steuercodes zum Ausführen allgemeiner Vorgänge wie Bewegen des Cursors, Scrollen des Bildschirms und Löschen des Bereichs. Verschiedene Arten von Terminals können sehr unterschiedliche Steuercodes verwenden und haben oft eine besondere Angewohnheit. 
Dies kann nützlich sein, wenn Sie eine einfache GUI erstellen oder mit Daten auf einem Server arbeiten möchten, auf den nur mit ssh zugegriffen werden kann. Sie können auch den Inhalt von CSV und DB anzeigen.
Angenommen, Sie haben die folgende CSV-Datei.
| ID | Prefecture | Capital | Population | Area | Density | 
|---|---|---|---|---|---|
| 1 | Aichi | Nagoya | 70,43,235 | 5,153.81 | 1,366 | 
| 2 | Akita | Akita | 11,89,215 | 11,612.11 | 102 | 
| 3 | Aomori | Aomori | 14,75,635 | 9,606.26 | 154 | 
| ... | ... | ... | ... | ... | ... | 
| 45 | Yamagata | Yamagata | 12,44,040 | 9,323.34 | 133 | 
| 46 | Yamaguchi | Yamaguchi | 15,28,107 | 6,110.76 | 250 | 
| 47 | Yamanashi | Kofu | 8,88,170 | 4,465.37 | 199 | 
Ich möchte eine GUI erstellen, die den Inhalt des Terminals anzeigen und die zu verarbeitende Präfektur auswählen kann.
main.py
# -*- coding: utf-8 -*-
import curses
import csv
from math import ceil
ROWS_PER_PAGE = 20
ENTER = ord( "\n" )
ESC = 27
DOWN = curses.KEY_DOWN
UP = curses.KEY_UP
class UI():
    def __init__(self, header, rows):
        super().__init__()
        self.header = header 
        self.rows = rows
        #Initialisieren
        self.screen = curses.initscr()
        curses.noecho()
        curses.cbreak()
        curses.start_color()
        self.screen.keypad(1)
        #Farbeinstellungen
        curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_CYAN)
        self.highlight_text = curses.color_pair(1) #Verwenden Sie die Paar-ID in der obigen Zeile
        self.normal_text = curses.A_NORMAL
        self.screen.border(0)
        curses.curs_set(0)
        self.rows_per_page = ROWS_PER_PAGE
        self.total_rows = len(self.rows)
        #Notieren Sie die Breite jeder Spalte
        self.widths = []
        #Randzeichnung
        self.tavnit = '|'
        self.separator = '+'
        for index, title in enumerate(self.header):
            #Machen Sie den Spaltentitel und den längsten Wert jeder Zeile zur Breite der Spalte
            max_col_length = max([len(row[index]) for row in self.rows])
            max_col_length = max(max_col_length, len(title))
            self.widths.append(max_col_length)
        #Rahmeneinstellungen
        for w in self.widths:
            #Es sieht aus wie das:
            # | %-2s | %-10s | %-10s | %-11s | %-9s | %-7s |
            self.tavnit += " %-"+"%ss |" % (w,)
            #Es sieht aus wie das:
            # +----+------------+------------+-------------+-----------+---------+
            self.separator += '-'*w + '--+'
        self.total_pages = int(ceil(self.total_rows / self.rows_per_page))
        self.position = 1
        self.page = 1
        #Nachricht angezeigt werden
        self.msg = 'Page: {}/{}'.format(self.page, self.total_pages)
    def end(self):
        curses.endwin()
    def draw(self):
        self.screen.erase()
        #Nachricht oben anzeigen
        self.screen.addstr(1, 2, self.msg, self.normal_text)
        #Rand auf dem Tisch
        self.screen.addstr(2, 2, self.separator, self.normal_text)
        #Kopfzeile anzeigen
        self.screen.addstr(3, 2, self.tavnit % tuple(self.header), self.normal_text)
        #Grenze zwischen Header und Inhalt
        self.screen.addstr(4, 2, self.separator, self.normal_text)
        #Zeichne jede Linie
        row_start = 1 + (self.rows_per_page * (self.page - 1))
        row_end = self.rows_per_page + 1 + (self.rows_per_page * (self.page - 1))
        for i in range(row_start, row_end):
            if i >= self.total_rows + 1:
                break
            row_number = i + (self.rows_per_page * (self.page - 1))
            #Linie markieren
            if (row_number == self.position + (self.rows_per_page * (self.page - 1))):
                color = self.highlight_text
            else:
                color = self.normal_text
            #Da gibt es 4 Zeilen wie Nachrichten und Rahmen oben+4
            draw_number = i - (self.rows_per_page * (self.page - 1)) + 4 #Da gibt es 4 Zeilen wie Nachrichten und Rahmen oben
            self.screen.addstr(draw_number , 2, self.tavnit % tuple(self.rows[i - 1]), color)
        #Unterer Rand der Tabelle,Da gibt es 4 Zeilen wie Nachrichten und Rahmen oben+4
        bottom = min(row_end, self.total_rows + 1) - (self.rows_per_page * (self.page - 1)) + 4
        self.screen.addstr(bottom, 2, self.separator, self.normal_text)
        self.screen.refresh()
    def down(self):
        if self.page == self.total_pages:
            if self.position < self.total_rows:
                self.position += 1
        else:
            if self.position < self.rows_per_page + (self.rows_per_page * (self.page - 1)):
                self.position += 1
            else:
                self.page += 1
                self.position = 1 + (self.rows_per_page * (self.page - 1))
                self.msg = 'Page: {}/{}'.format(self.page, self.total_pages)
        self.draw()
    def up(self):
        if self.page == 1:
            if self.position > 1:
                self.position -= 1
        else:
            if self.position > (1 + (self.rows_per_page * (self.page - 1))):
                self.position -= 1
            else:
                self.page -= 1
                self.position = self.rows_per_page + (self.rows_per_page * (self.page - 1))
                self.msg = 'Page: {}/{}'.format(self.page, self.total_pages)
        self.draw()
    def esc(self):
        self.end()
    def enter(self):
        #Was Sie hier machen wollen
        prefecture_id = self.rows[self.position - 1][0]
        prefecture = self.rows[self.position - 1][1]
        self.msg = 'Page: {}/{} ({} {} was selected.)' \
                .format(self.page, self.total_pages, prefecture_id, prefecture)
        self.draw()
    def loop(self):
        #Erkennt den eingegebenen Schlüssel
        key = self.screen.getch()
        while 1:
            if key == ENTER:
                self.enter()
            elif key == ESC:
                self.esc()
                break
            elif key == DOWN:
                self.down()
            elif key == UP:
                self.up()
            key = self.screen.getch()
if __name__ == '__main__':
    with open('prefectures.csv') as f:
        reader = csv.reader(f)
        data = list(reader)
    header = data[0]
    rows = data[1:]
    
    ui = UI(header, rows)
    ui.draw()
    ui.loop()
$ python main.py
Die maximale Anzahl von Zeilen auf der Seite beträgt 20.
Sie können mit ↑ und ↓ scrollen.
Wenn Sie die Eingabetaste drücken (Zurück), werden die Informationen der entsprechenden Präfektur in der Nachricht angezeigt.
Beenden Sie die GUI mit "ESC".

Recommended Posts