Ejecutando comandos del sistema en Python usando curses y panel, y regrese al menú anterior

StackOverflow https://stackoverflow.com/questions/19833315

Pregunta

Estoy codificando un script de Python usando varias herramientas de Commanline como TOP, por lo que necesito una retroalimentación visual adecuada. Ahora es el momento de darle un menú, así que aquí viene el problema.

Encontré aquí un gran enfoque De lo que necesito, pero cada intente mostrar comentarios antes de volver al menú anterior es inútil.

Solo necesito menús, submenús, comandos de lanzamiento, terminarlo y volver al menú anterior. Una gran ventaja sería ejecutarlos en una división del término.

¿Hay algún patrón/esqueleto/material/lo que sea para usar como plantilla para mostrar varios tipos de widget con una salida predecible?

Aquí hay un ejemplo de código, que dos ejemplos de funciones para ejecutar:

#!/usr/bin/env python2                                                       

import curses                                                                
from curses import panel                                                     

class Menu(object):                                                          

    def __init__(self, items, stdscreen):                                    
        self.window = stdscreen.subwin(0,0)                                  
        self.window.keypad(1)                                                
        self.panel = panel.new_panel(self.window)                            
        self.panel.hide()                                                    
        panel.update_panels()                                                

        self.position = 0                                                    
        self.items = items                                                   
        self.items.append(('exit','exit'))                                   

    def navigate(self, n):                                                   
        self.position += n                                                   
        if self.position < 0:                                                
            self.position = 0                                                
        elif self.position >= len(self.items):                               
            self.position = len(self.items)-1                                

    def display(self):                                                       
        self.panel.top()                                                     
        self.panel.show()                                                    
        self.window.clear()                                                  

        while True:                                                          
            self.window.refresh()                                            
            curses.doupdate()                                                
            for index, item in enumerate(self.items):                        
                if index == self.position:                                   
                    mode = curses.A_REVERSE                                  
                else:                                                        
                    mode = curses.A_NORMAL                                   

                msg = '%d. %s' % (index, item[0])                            
                self.window.addstr(1+index, 1, msg, mode)                    

            key = self.window.getch()                                        

            if key in [curses.KEY_ENTER, ord('\n')]:                         
                if self.position == len(self.items)-1:                       
                    break                                                    
                else:                                                        
                    self.items[self.position][1]()                           

            elif key == curses.KEY_UP:                                       
                self.navigate(-1)                                            

            elif key == curses.KEY_DOWN:                                     
                self.navigate(1)                                             

        self.window.clear()                                                  
        self.panel.hide()                                                    
        panel.update_panels()                                                
        curses.doupdate()

######################################################### !# 
######################################################### !#    
############# HERE MY FUNCTIONS examples
############  Everithing works OK, but displays it awfully

def GetPid(name):
    import subprocess
    command= str(("""pgrep %s""") % name )
    p = subprocess.Popen(command, shell = True, stdout = subprocess.PIPE)
    procs = []
    salida = p.stdout
    for line in salida:
        procs.append(str.strip(line))

    return procs


def top():
    os.system("top")    

def menuGP():
    print GetPid("top")  


######################################################### !# 

class MyApp(object):                                                         

    def __init__(self, stdscreen):                                           
        self.screen = stdscreen                                              
        curses.curs_set(0)                                                   

        submenu_items = [                                                    
                ('beep', curses.beep),                                       
                ('top', top)                                      
                ]                                                            
        submenu = Menu(submenu_items, self.screen)                           

        main_menu_items = [                                                  
                ('get PID', GetPid),                                       
                ('submenu', submenu.display)                                 
                ]                                                            
        main_menu = Menu(main_menu_items, self.screen)                       
        main_menu.display()                                                  

if __name__ == '__main__':                                                       
    curses.wrapper(MyApp)

Gracias en Assise (y perdón por mi maldito inglés)

¿Fue útil?

Solución

Realmente tienes dos opciones. Uno puede dejar el modo Cursas, ejecutar su programa y luego reanudar las maldiciones. Dos, puede ejecutar su programa de forma asincrónica, analizar su salida y escribirlo en la pantalla.

La buena noticia sobre la primera opción es que en realidad no necesita escribir ningún método Fancy Save_state / Load_state para la interfaz de usuario. Maldiciones hace esto por ti. Aquí hay un ejemplo simple para mostrar mi punto

import curses, time, subprocess

class suspend_curses():
    """Context Manager to temporarily leave curses mode"""

    def __enter__(self):
        curses.endwin()

    def __exit__(self, exc_type, exc_val, tb):
        newscr = curses.initscr()
        newscr.addstr('Newscreen is %s\n' % newscr)
        newscr.refresh()
        curses.doupdate()

def main(stdscr):
    stdscr.addstr('Stdscreen is %s\n' % stdscr)
    stdscr.refresh()
    time.sleep(1)

    with suspend_curses():
        subprocess.call(['ls'])
        time.sleep(1)

    stdscr.refresh()
    time.sleep(5)

curses.wrapper(main)

Si ejecuta el ejemplo, notará que la pantalla creada por curses.wrapper y el creado en curses.initscr Cuando se reanudan son el mismo objeto. Es decir, la ventana devuelta por curses.initscr es un singleton. Esto nos permite salir de maldiciones y reanudar como anteriormente sin tener que actualizar cada widget self.screen Referencias cada vez.

La segunda opción es mucho más involucrada pero también mucho más flexible. Lo siguiente es solo para representar la idea básica.

class procWidget():
    def __init__(self, stdscr):
        # make subwindow / panel
        self.proc = subprocess.Popen(my_args, stdout=subprocess.PIPE)

    def update(self):
        data = self.proc.stdout.readline()
        # parse data as necessary
        # call addstr() and refresh()

Luego en algún lugar de su programa querrá llamar update en todos sus procesos en un temporizador. Esto le brinda la opción de hacer su subwindow de cualquier tamaño/lugar para que pueda tener tantos procesos que se ajusten. Tendrá que agregar algún manejo para cuando el proceso termine y otros eventos similares, por supuesto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top