python - 使用 curses 和 panel 在 Python 中运行系统命令,并返回到上一个菜单

标签 python subprocess panel curses

我正在使用多个命令行工具(如 top)编写 python 脚本,因此我需要适当的视觉反馈。现在是时候给它一个菜单了,所以问题来了。

I found here a great approach我需要的东西,但每次尝试在返回上一个菜单之前显示反馈都是徒劳的。

我只需要菜单、子菜单、启动命令、终止它并返回上一个菜单。一个巨大的好处是在学期的 split 中运行它们。

是否有任何模式/骨架/东西/任何东西可以用作模板来显示几种具有可预测输出的小部件?

这是一个代码示例,其中有两个要运行的函数示例:

#!/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)

谢谢你的建议(抱歉我的英语不好)

最佳答案

你真的有两个选择。一种是你可以离开 curses 模式,执行你的程序,然后恢复 curses。第二,您可以异步执行您的程序,解析其输出并将其写入屏幕。

第一个选项的好消息是您实际上不需要为 ui 编写任何花哨的 save_state/load_state 方法。 Curses 会为你做这件事。这是一个简单的例子来说明我的观点

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)

如果你运行这个例子,你会注意到 curses.wrapper 创建的屏幕和恢复时在 curses.initscr 中创建的屏幕是同一个对象。也就是说,curses.initscr 返回的窗口是一个单例。这让我们可以退出 curses 并像上面那样继续,而不必每次都更新每个小部件的 self.screen 引用。

第二个选项更复杂,但也更灵活。以下仅代表基本思想。

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

然后在您的程序中的某处,您将希望在计时器上的所有 procWidget 上调用 update。这使您可以选择将子窗口设置为任意大小/位置,这样您就可以拥有尽可能多的 procWidgets。当然,您必须为进程终止和其他类似事件添加一些处理。

关于python - 使用 curses 和 panel 在 Python 中运行系统命令,并返回到上一个菜单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19833315/

相关文章:

c# - Visual Studio 设计重叠面板

python - 如何逐字读取文件

python - 计算 pandas 中的 Tf-Idf 分数?

python - 我无法使用子进程运行临时文件夹中的文件吗?

python - 运行 python 的子进程出现导入错误

twitter-bootstrap-3 - 为什么可折叠 Bootstrap 面板中的表格会改变宽度?

具有重复元素的列表的 Python 深层复制

python - 使用 PySpark 将复杂 RDD 转换为扁平化 RDD

python - 在 subprocess.call() 中使用带反引号的命令替换

javascript - 从 ExtJS 网格面板获取所有行