更新屏幕时,Python/curses用户输入 [英] Python/curses user input while updating screen

查看:74
本文介绍了更新屏幕时,Python/curses用户输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用python/curses编写应用程序UI,我想知道是否可以要求用户在UI不断更新时按下键(cbreak模式)以隐藏或显示某些面板或窗口.

I'm currently coding an app U.I with python/curses and I was wondering if it is possible to ask the user to press keys (cbreak mode) to hide or show some panels or windows while the U.I is continuously updating.

我阅读了有关curses的官方python文档并进行了一些尝试,但是即使使用了cbreak模式和非阻塞输入模式(nodelay),我也无法使其正常工作(我成功地获得了用户输入,但以阻止不是我想要的UI为代价).

I read the official python docs about curses and made some tries but even with the use of the cbreak mode and the non-blocking input mode (nodelay) activated I am unable to make it work properly (I succeed in getting the user input but at the expense of blocking the U.I that is not what I want).

所以我的问题很简单,可能吗?如果可以,怎么办?

So my question is simple, is it possible ? And if yes, how ?

我可能误读了文档,但没有找到任何替代文档或示例.

I may have mis-read the docs but I haven't found any alternative docs or example about it.

我曾考虑过使应用程序具有多线程功能,但在这种情况下,我没有看到这对我有什么帮助.

I thought about making the app multi-threaded but I didn't see how this can help me in this case.

感谢您的帮助,建议或指向详细文档的指针.

Thank you for your help, advices or pointer to a detailed doc.

我最终得到了以下多线程代码,但并不令人满意. U.I已按原样提供,但刷新后显示变暗.

I finally ended up with the following multi-threaded code but it's not satisfying. The U.I is feeded as it has to be but after refreshing the display is borked.

我也不明白为什么当隐藏被考虑的面板时curses.panel.hidden()返回False的原因.似乎刷新与面板关联的窗口会取消隐藏面板或类似的东西.此时我真的迷路了!

I also do not understand why the curses.panel.hidden() returns False while the considered panel is hidden. It seems that refreshing the window associated with the panel unhide the panel or something like that. I'm really lost at this point !

import threading
import curses, curses.panel
import random
import time

gui = None

class ui:
    def __init__(self):
        self.feeder = feeder(self)
        self.stdscr = curses.initscr()
        curses.noecho()
        curses.cbreak()
        curses.curs_set(0)
        self.stdscr.keypad(1)

        self.win1 = curses.newwin(10, 50, 0, 0)    
        self.win1.border(0)
        self.pan1 = curses.panel.new_panel(self.win1)
        self.win2 = curses.newwin(10, 50, 0, 0)    
        self.win2.border(0)
        self.pan2 = curses.panel.new_panel(self.win2)
        self.win3 = curses.newwin(10, 50, 12, 0)
        self.win3.border(0)
        self.pan3 = curses.panel.new_panel(self.win3)

        self.win1.addstr(1, 1, "Window 1")
        self.win2.addstr(1, 1, "Window 2")
        self.win3.addstr(1, 1, "Press 's' to switch windows or 'q' to quit.")


        self.pan1.hide()
        self.win1.refresh()

        curses.panel.update_panels()
        self.win2.refresh()
        self.feeder.start()


    def ask(self):
        while True:
            self.win3.addstr(5,1, "Hidden = win1: "+str(self.pan1.hidden())+\
                             "win2:"+str(self.pan2.hidden()), 0)
            self.win3.refresh()
            k = self.win3.getkey()
            if k == 's':
                if self.pan1.hidden():
                    self.pan2.hide()
                    self.pan1.show()
                    self.win1.refresh()
                    self.win3.addstr(2, 1, "Pan1 restored")
                else:
                    self.pan1.hide()
                    self.pan2.show()
                    self.win2.refresh()
                    self.win3.addstr(2, 1, "Pan2 restored")
                self.win3.addstr(5,1, "Hidden = win1: "+\
                                 str(self.pan1.hidden())+\
                                 " win2:"+str(self.pan2.hidden()), 0)

            elif  k == 'q':
                break        
        self.quit_ui()

    def quit_ui(self):
        self.feeder.stop()
        curses.nocbreak()
        self.stdscr.keypad(0)
        curses.curs_set(1)
        curses.echo()
        curses.endwin()
        exit(0)

    def display_data(self, window, data):
        window.addstr(3, 1, data, 0)



class feeder(threading.Thread):
    # Fake U.I feeder
    def __init__(self, ui):
        super(feeder, self).__init__()
        self.running = False
        self.ui = ui
        self.count = 0

    def stop(self):
        self.running = False

    def run(self):
        self.running = True
        self.feed()

    def feed(self):
        while self.running:
            self.ui.win1.addstr(3, 1, str(self.count)+\
                                ": "+str(int(round(random.random()*9999))))
            self.ui.win1.addstr(4, 1, str(self.running))
            self.ui.win2.addstr(3, 1, str(self.count)+\
                                ": "+str(int(round(random.random()*9999))))
            self.ui.win2.addstr(4, 1, str(self.running))
            time.sleep(0.5)
            self.count += 1


if __name__ == "__main__":
    gui = ui()
    gui.ask()

推荐答案

我最终通过在double while循环中从sys.stdin中读取一个字节,然后避免使用另一个线程来使其成功运行. 以下代码可能无法在MS Windows上运行,并且由于我不是专业开发人员,因此它可能未经过优化或引发了未捕获的错误,但这只是为了使我理解事情的工作而编写的草稿(尽管欢迎发表评论) ). 特别感谢Paul Griffiths将我引导到sys.stdin.

I finally succeed in make it work by reading one byte from sys.stdin in a double while loop and then avoiding the use of another thread. The following code may not work on MS Windows and as I'm not a professional developer it may be un-optimized or throw un-catched errors but it is just a draft made to make me understand how things work (though, comment are welcome). Special thanks to Paul Griffiths who guided me to sys.stdin.

#!/usr/bin/python
# -*- coding: iso-8859-1 -*-

import curses, curses.panel
import random
import time
import sys
import select

gui = None

class ui:
    def __init__(self):
        self.stdscr = curses.initscr()
        curses.noecho()
        curses.cbreak()
        curses.curs_set(0)
        self.stdscr.keypad(1)

        self.win1 = curses.newwin(10, 50, 0, 0)    
        self.win1.border(0)
        self.pan1 = curses.panel.new_panel(self.win1)
        self.win2 = curses.newwin(10, 50, 0, 0)    
        self.win2.border(0)
        self.pan2 = curses.panel.new_panel(self.win2)
        self.win3 = curses.newwin(10, 50, 12, 0)
        self.win3.border(0)
        self.pan3 = curses.panel.new_panel(self.win3)

        self.win1.addstr(1, 1, "Window 1")
        self.win2.addstr(1, 1, "Window 2")
        self.win3.addstr(1, 1, "Press 's' to switch windows or 'q' to quit.")

        self.pan1.hide()

    def refresh(self):
        curses.panel.update_panels()
        self.win2.refresh()
        self.win1.refresh()

    def switch_pan(self):
        if self.pan1.hidden():
            self.pan2.bottom()
            self.pan2.hide()
            self.pan1.top()
            self.pan1.show()
        else:
            self.pan1.bottom()
            self.pan1.hide()
            self.pan2.top()
            self.pan2.show()

        self.refresh()

    def quit_ui(self):
        curses.nocbreak()
        self.stdscr.keypad(0)
        curses.curs_set(1)
        curses.echo()
        curses.endwin()
        print "UI quitted"
        exit(0)


class feeder:
    # Fake U.I feeder
    def __init__(self):
        self.running = False
        self.ui = ui()
        self.count = 0

    def stop(self):
        self.running = False

    def run(self):
        self.running = True
        self.feed()

    def feed(self):
        while self.running :
            while sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
                line = sys.stdin.read(1)
                if line.strip() == "q":
                    self.stop()
                    self.ui.quit_ui()
                    break
                elif line.strip() == "s":
                    self.ui.switch_pan()

            self.ui.win1.addstr(3, 1, str(self.count)+\
                                ": "+str(int(round(random.random()*999))))
            self.ui.win1.addstr(4, 1, str(self.running))
            self.ui.win2.addstr(3, 1, str(self.count)+\
                                ": "+str(int(round(random.random()*999))))
            self.ui.win2.addstr(4, 1, str(self.running))
            self.ui.refresh()
            time.sleep(0.1)
            self.count += 1

if __name__ == "__main__":
    f = feeder()
    f.run()

这篇关于更新屏幕时,Python/curses用户输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆