我正在使用多个命令行工具(如 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/