Selon le Document officiel,
La bibliothèque curses fournit le dessin d'écran indépendant du terminal et le traitement du clavier pour les terminaux basés sur du texte (terminaux) tels que les VT100, les consoles Linux et les terminaux d'émulation fournis par divers programmes. Le terminal prend en charge divers codes de commande pour effectuer des opérations courantes telles que déplacer le curseur, faire défiler l'écran et effacer la zone. Différents types de terminaux peuvent utiliser des codes de contrôle très différents, souvent avec des bizarreries uniques. 
Cela peut être utile lorsque vous souhaitez créer une interface graphique simple ou lorsque vous souhaitez travailler avec des données sur un serveur accessible uniquement avec ssh. Vous pouvez également afficher le contenu de CSV et DB.
Par exemple, supposons que vous ayez le [fichier csv] suivant (https://raw.githubusercontent.com/hrdrq/curses_sample/master/prefectures.csv).
| 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 | 
Je souhaite créer une interface graphique pouvant afficher le contenu sur le terminal et sélectionner la préfecture à traiter.
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
        #Initialisation
        self.screen = curses.initscr()
        curses.noecho()
        curses.cbreak()
        curses.start_color()
        self.screen.keypad(1)
        #Paramètres de couleur
        curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_CYAN)
        self.highlight_text = curses.color_pair(1) #Utilisez l'identifiant de paire dans la ligne ci-dessus
        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)
        #Enregistrez la largeur de chaque colonne
        self.widths = []
        #Dessin de bordure
        self.tavnit = '|'
        self.separator = '+'
        for index, title in enumerate(self.header):
            #Faire du titre de la colonne et de la valeur la plus longue de chaque ligne la largeur de la colonne
            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)
        #Paramètres de bordure
        for w in self.widths:
            #Cela ressemble à ceci:
            # | %-2s | %-10s | %-10s | %-11s | %-9s | %-7s |
            self.tavnit += " %-"+"%ss |" % (w,)
            #Cela ressemble à ceci:
            # +----+------------+------------+-------------+-----------+---------+
            self.separator += '-'*w + '--+'
        self.total_pages = int(ceil(self.total_rows / self.rows_per_page))
        self.position = 1
        self.page = 1
        #Message à afficher
        self.msg = 'Page: {}/{}'.format(self.page, self.total_pages)
    def end(self):
        curses.endwin()
    def draw(self):
        self.screen.erase()
        #Afficher le message en haut
        self.screen.addstr(1, 2, self.msg, self.normal_text)
        #Bordure sur la table
        self.screen.addstr(2, 2, self.separator, self.normal_text)
        #Afficher en-tête
        self.screen.addstr(3, 2, self.tavnit % tuple(self.header), self.normal_text)
        #Frontière entre l'en-tête et le contenu
        self.screen.addstr(4, 2, self.separator, self.normal_text)
        #Tracez chaque ligne
        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))
            #Mettre en évidence la ligne
            if (row_number == self.position + (self.rows_per_page * (self.page - 1))):
                color = self.highlight_text
            else:
                color = self.normal_text
            #Puisqu'il y a 4 lignes telles que des messages et des bordures au-dessus+4
            draw_number = i - (self.rows_per_page * (self.page - 1)) + 4 #Puisqu'il y a 4 lignes telles que des messages et des bordures au-dessus
            self.screen.addstr(draw_number , 2, self.tavnit % tuple(self.rows[i - 1]), color)
        #Bordure inférieure du tableau,Puisqu'il y a 4 lignes telles que des messages et des bordures au-dessus+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):
        #Ce que tu veux faire ici
        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):
        #Détecte la clé saisie
        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
Le nombre maximum de lignes sur la page est de 20.
Vous pouvez faire défiler avec ↑ et ↓.
ʻEnter (return) affichera les informations de la préfecture correspondante dans le message.  Quittez l'interface graphique avec ʻESC.

Recommended Posts