[PYTHON] Créez une interface graphique sur le terminal à l'aide de curses

Qu'est-ce que les malédictions

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.

Chose que tu veux faire

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.

la mise en oeuvre

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()

Courir

$ python main.py

résultat

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.

result

Recommended Posts

Créez une interface graphique sur le terminal à l'aide de curses
Créer une interface graphique python à l'aide de tkinter
Créer un graphique à l'aide du module Sympy
[Python] Une barre de progression sur le terminal
Comment écrire une interface graphique à l'aide de la commande maya
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 1 ~
Créez un code QR pour l'URL sous Linux
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 2 ~
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 3 ~
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 4 ~
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 5 ~
Rechercher la table à l'aide de sqlalchemy et créer un dictionnaire
Créer une salle de classe sur Jupyterhub
Créer un nouveau csv avec des pandas basé sur le csv local
Créez un robot de réponse automatique en temps réel à l'aide de l'API Twitter Streaming
J'ai fait un modèle VGG16 en utilisant TensorFlow (en chemin)
Créer un environnement Python sur Mac (2017/4)
Créer un dictionnaire imbriqué à l'aide de defaultdict
Créer un service SlackBot sur Pepper
Créer un environnement Linux sur Windows 10
Créer un environnement python dans centos
Utilisation d'une console série sur Ubuntu 20.04
Remarques sur l'utilisation de matplotlib sur le serveur
Créez un wrapper de langage C à l'aide de Boost.Python
Contrôlez le moteur avec un pilote de moteur en utilisant python sur Raspberry Pi 3!
Utilisez sqlalchemy pour rechercher la table DB et créer un Dataflame pour les pandas
[Ev3dev] Créez un programme qui capture LCD (écran) en utilisant python
Créez des raccourcis pour exécuter des fichiers Python sur le terminal avec VScode
Créez un environnement python sur votre Mac
Créer une application graphique avec Tkinter de Python
Créer une application à l'aide de l'API Spotify
Estimer la probabilité qu'une pièce apparaisse en utilisant MCMC
Créer un enregistrement avec des pièces jointes dans KINTONE à l'aide du module de requêtes Python
Créer une machine virtuelle Linux sous Windows
Créer un bloc de données à partir d'Excel à l'aide de pandas
Ajouter une couche à l'aide du backend Keras
[2015/11/19] Comment enregistrer un service localement à l'aide du SDK python avec naoqi os
Comment créer rapidement un environnement d'analyse morphologique à l'aide d'Elasticsearch sur macOS Sierra
Essayez de tracer la concentration environnementale des composés organiques du fluor sur une carte à l'aide de données ouvertes
Créez une API REST à l'aide du modèle appris dans Lobe et TensorFlow Serving.
Utilisation du capteur de température numérique à 1 fil DS18B20 avec Raspberry Pi de Python
[AWS Lambda] Créer un package de déploiement à l'aide de l'image Amazon Linux Docker
Une histoire addictive lors de l'utilisation de tensorflow sur Android
Créer un fichier GIF en utilisant Pillow en Python
Créer un fichier exécutable GUI créé avec tkinter
Essayez d'utiliser le code QR avec Raspberry Pi
Remarques sur la personnalisation de la classe de liste de dict
Créons une API REST en utilisant SpringBoot + MongoDB
Python: essayez d'utiliser l'interface utilisateur sur Pythonista 3 sur iPad
Vous pouvez facilement créer une interface graphique même avec Python
Créer un arbre phylogénétique à partir de Biopyton en utilisant ClustalW2
Créer une carte Web en utilisant Python et GDAL
Mise en évidence de la syntaxe sur la ligne de commande à l'aide de Pygments
[Venv] Créer un environnement virtuel python sur Ubuntu
Essayez de créer une nouvelle commande sous Linux
Créez des graphiques 3D interactifs sur Jupyter Lab à l'aide de matplotlib
Sonnez le buzzer en utilisant python sur Raspberry Pi 3!
Créer un système de notification des visiteurs à l'aide de Raspberry Pi