简体   繁体   English

如何在while循环期间获取用户输入而不阻塞

[英]How to get user input during a while loop without blocking

I'm trying to write a while loop that constantly updates the screen by using os.system("clear") and then printing out a different text message every few seconds. 我正在尝试编写一个while循环,通过使用os.system(“clear”)不断更新屏幕,然后每隔几秒打印一个不同的文本消息。 How do I get user input during the loop? 如何在循环期间获得用户输入? raw_input() just pauses and waits, which is not the functionality I want. raw_input()只是暂停和等待,这不是我想要的功能。

import os
import time

string = "the fox jumped over the lazy dog"
words = string.split(" ")
i = 0 

while 1:
    os.system("clear")
    print words[i]
    time.sleep(1)
    i += 1
    i = i%len(words)

I would like to be able to press 'q' or 'p' in the middle to quit and pause respectively. 我希望能够在中间按'q'或'p'分别退出和暂停。

The select module in Python's standard library may be what you're looking for -- standard input has FD 0, though you may also need to put a terminal in "raw" (as opposed to "cooked") mode, on unix-y systems, to get single keypresses from it as opposed to whole lines complete with line-end. Python标准库中的select模块可能正是您所需要的 - 标准输入具有FD 0,但您可能还需要在unix-y上将终端设置为“raw”(而不是“cooked”)模式系统,从它获得单个按键,而不是整行与行结束。 If on Windows, msvcrt , also in Python standard library, has all the functionality you need -- msvcrt.kbhit() tells you if any keystroke is pending, and, if so, msvcrt.getch() tells you what character it is. 如果在Windows上, msvcrt (也在Python标准库中)具有您需要的所有功能 - msvcrt.kbhit()告诉您是否有任何键击未决,如果是, msvcrt.getch()告诉您它是什么字符。

您还可以查看其中一个可用的配方 ,它为您提供了Unix和Windows所需的功能。

You can do that with threads, here is a basic example : 你可以用线程做到这一点,这是一个基本的例子:

import threading, os, time, itertools, Queue

# setting a cross platform getch like function
# thks to the Python Cookbook
# why isn't standard on this battery included language ?
try : # on windows
    from msvcrt import getch
except ImportError : # on unix like systems
    import sys, tty, termios
    def getch() :
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try :
            tty.setraw(fd)
            ch = sys.stdin.read(1)
        finally :
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch

# this will allow us to communicate between the two threads
# Queue is a FIFO list, the param is the size limit, 0 for infinite
commands = Queue.Queue(0)

# the thread reading the command from the user input     
def control(commands) :

    while 1 :

        command = getch()
        commands.put(command) # put the command in the queue so the other thread can read it

        #  don't forget to quit here as well, or you will have memory leaks
        if command == "q" :
            break


# your function displaying the words in an infinite loop
def display(commands):

    string = "the fox jumped over the lazy dog"
    words = string.split(" ")
    pause = False 
    command = ""

    # we create an infinite generator from you list
    # much better than using indices
    word_list = itertools.cycle(words) 

    # BTW, in Python itertools is your best friend

    while 1 :

        # parsing the command queue
        try:
           # false means "do not block the thread if the queue is empty"
           # a second parameter can set a millisecond time out
           command = commands.get(False) 
        except Queue.Empty, e:
           command = ""

        # behave according to the command
        if command == "q" :
            break

        if command == "p" :
            pause = True

        if command == "r" :
            pause = False

        # if pause is set to off, then print the word
        # your initial code, rewritten with a generator
        if not pause :
            os.system("clear")
            print word_list.next() # getting the next item from the infinite generator 

        # wait anyway for a second, you can tweak that
        time.sleep(1)



# then start the two threads
displayer = threading.Thread(None, # always to None since the ThreadGroup class is not implemented yet
                            display, # the function the thread will run
                            None, # doo, don't remember and too lazy to look in the doc
                            (commands,), # *args to pass to the function
                             {}) # **kwargs to pass to the function

controler = threading.Thread(None, control, None, (commands,), {})

if __name__ == "__main__" :
    displayer.start()
    controler.start()

As usual, using threads is tricky, so be sure you understand what you do before coding that. 像往常一样,使用线程很棘手,因此请确保在编码之前了解您的操作。

Warning : Queue will be rename in queue in Python 3. 警告:队列将在Python 3中重命名为队列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM