developer tip

회전하는 명령 줄 커서를 만드는 방법은 무엇입니까?

copycodes 2020. 12. 10. 20:42
반응형

회전하는 명령 줄 커서를 만드는 방법은 무엇입니까?


Python을 사용하여 터미널에서 회전하는 커서를 인쇄하는 방법이 있습니까?


이와 같이 터미널이 \ b를 처리한다고 가정합니다.

import sys
import time

def spinning_cursor():
    while True:
        for cursor in '|/-\\':
            yield cursor

spinner = spinning_cursor()
for _ in range(50):
    sys.stdout.write(next(spinner))
    sys.stdout.flush()
    time.sleep(0.1)
    sys.stdout.write('\b')

사용하기 쉬운 API (별도의 스레드에서 스피너를 실행합니다) :

import sys
import time
import threading

class Spinner:
    busy = False
    delay = 0.1

    @staticmethod
    def spinning_cursor():
        while 1: 
            for cursor in '|/-\\': yield cursor

    def __init__(self, delay=None):
        self.spinner_generator = self.spinning_cursor()
        if delay and float(delay): self.delay = delay

    def spinner_task(self):
        while self.busy:
            sys.stdout.write(next(self.spinner_generator))
            sys.stdout.flush()
            time.sleep(self.delay)
            sys.stdout.write('\b')
            sys.stdout.flush()

    def __enter__(self):
        self.busy = True
        threading.Thread(target=self.spinner_task).start()

    def __exit__(self, exception, value, tb):
        self.busy = False
        time.sleep(self.delay)
        if exception is not None:
            return False

이제 with코드의 어느 곳에서나 블록 에서 사용하십시오 .

with Spinner():
  # ... some long-running operations
  # time.sleep(3) 

좋은 파이썬적인 방법은 itertools.cycle을 사용하는 것입니다.

import itertools, sys
spinner = itertools.cycle(['-', '/', '|', '\\'])
while True:
    sys.stdout.write(spinner.next())  # write the next character
    sys.stdout.flush()                # flush stdout buffer (actual character display)
    sys.stdout.write('\b')            # erase the last written char

또한 http://www.interclasse.com/scripts/spin.php 와 같이 긴 함수 호출 중에 스레딩을 사용하여 스피너를 표시 할 수 있습니다 .


해결책 :

import sys
import time

print "processing...\\",
syms = ['\\', '|', '/', '-']
bs = '\b'

for _ in range(10):
    for sym in syms:
        sys.stdout.write("\b%s" % sym)
        sys.stdout.flush()
        time.sleep(.5)

핵심은 백 스페이스 문자 '\ b'를 사용하고 stdout을 플러시하는 것입니다.


물론 가능합니다. 그것은 백 스페이스 문자 (인쇄 단지 질문 \b그것의 회전과 같은 "커서"모양을 만드는 것이 네 문자 사이) ( -, \, |, /).


curses 모듈. addstr () 및 addch () 함수를 살펴 보겠습니다. 그래도 사용하지 않았습니다.


고급 콘솔 조작을 위해 유닉스에서는 curses python module 을 사용할 수 있으며 Windows에서는 curses 라이브러리와 동등한 기능을 제공하는 WConio사용할 수 있습니다 .


멋진 progressbar모듈 -http : //code.google.com/p/python-progressbar/ 사용 RotatingMarker.


#!/usr/bin/env python

import sys

chars = '|/-\\'

for i in xrange(1,1000):
    for c in chars:
        sys.stdout.write(c)
        sys.stdout.write('\b')
        sys.stdout.flush()

주의 사항 : 내 경험상 이것은 모든 터미널에서 작동하지 않습니다. Unix / Linux에서이 작업을 수행하는 더 강력한 방법은 Windows에서는 작동하지 않는 curses 모듈 을 사용하는 것 입니다. 백그라운드에서 진행되는 실제 처리로 속도를 늦추고 싶을 것입니다.


import sys
def DrowWaitCursor(self, counter):
    if counter % 4 == 0:
        print("/",end = "")
    elif counter % 4 == 1:
        print("-",end = "")
    elif counter % 4 == 2:
        print("\\",end = "")
    elif counter % 4 == 3:
        print("|",end = "")
    sys.stdout.flush()
    sys.stdout.write('\b') 

매개 변수가있는 함수를 사용하는 또 다른 솔루션이 될 수도 있습니다.


여기 있습니다-간단하고 명확합니다.

import sys
import time

idx = 0
cursor = ['|','/','-','\\'] #frames of an animated cursor

while True:
    sys.stdout.write(cursor[idx])
    sys.stdout.write('\b')
    idx = idx + 1

    if idx > 3:
        idx = 0

    time.sleep(.1)

조잡하지만 간단한 솔루션 :

import sys
import time
cursor = ['|','/','-','\\']
for count in range(0,1000):
  sys.stdout.write('\b{}'.format(cursor[count%4]))
  sys.stdout.flush()
  # replace time.sleep() with some logic
  time.sleep(.1)

명백한 한계가 있지만 다시 말하지만, 조잡합니다.


전체 응용 프로그램에서 공유하는 일반 Singleton을 만들었습니다.

from itertools import cycle
import threading
import time


class Spinner:
    __default_spinner_symbols_list = ['|-----|', '|#----|', '|-#---|', '|--#--|', '|---#-|', '|----#|']

def __init__(self, spinner_symbols_list: [str] = None):
    spinner_symbols_list = spinner_symbols_list if spinner_symbols_list else Spinner.__default_spinner_symbols_list
    self.__screen_lock = threading.Event()
    self.__spinner = cycle(spinner_symbols_list)
    self.__stop_event = False
    self.__thread = None

def get_spin(self):
    return self.__spinner

def start(self, spinner_message: str):
    self.__stop_event = False
    time.sleep(0.3)

    def run_spinner(message):
        while not self.__stop_event:
            print("\r{message} {spinner}".format(message=message, spinner=next(self.__spinner)), end="")
            time.sleep(0.3)

        self.__screen_lock.set()

    self.__thread = threading.Thread(target=run_spinner, args=(spinner_message,), daemon=True)
    self.__thread.start()

def stop(self):
    self.__stop_event = True
    if self.__screen_lock.is_set():
        self.__screen_lock.wait()
        self.__screen_lock.clear()
        print("\r", end="")

    print("\r", end="")

if __name__ == '__main__':
    import time
    # Testing
    spinner = Spinner()
    spinner.start("Downloading")
    # Make actions
    time.sleep(5) # Simulate a process
    #
    spinner.stop()

원래 버전에는 문제가 거의 없었기 때문에 @Victor Moyseenko에서 개선 된 버전

  1. 회전이 완료된 후 스피너의 캐릭터를 떠났습니다.
  2. 때로는 다음 출력의 첫 번째 문자도 제거됩니다.
  3. 출력에 threading.Lock ()을 추가하여 드문 경쟁 조건을 피합니다.
  4. tty를 사용할 수 없을 때 더 간단한 출력으로 돌아갑니다 (회전 없음).
import sys
import threading
import itertools
import time

class Spinner:

    def __init__(self, message, delay=0.1):
        self.spinner = itertools.cycle(['-', '/', '|', '\\'])
        self.delay = delay
        self.busy = False
        self.spinner_visible = False
        sys.stdout.write(message)

    def write_next(self):
        with self._screen_lock:
            if not self.spinner_visible:
                sys.stdout.write(next(self.spinner))
                self.spinner_visible = True
                sys.stdout.flush()

    def remove_spinner(self, cleanup=False):
        with self._screen_lock:
            if self.spinner_visible:
                sys.stdout.write('\b')
                self.spinner_visible = False
                if cleanup:
                    sys.stdout.write(' ')       # overwrite spinner with blank
                    sys.stdout.write('\r')      # move to next line
                sys.stdout.flush()

    def spinner_task(self):
        while self.busy:
            self.write_next()
            time.sleep(self.delay)
            self.remove_spinner()

    def __enter__(self):
        if sys.stdout.isatty():
            self._screen_lock = threading.Lock()
            self.busy = True
            self.thread = threading.Thread(target=self.spinner_task)
            self.thread.start()

    def __exit__(self, exception, value, tb):
        if sys.stdout.isatty():
            self.busy = False
            self.remove_spinner(cleanup=True)
        else:
            sys.stdout.write('\r')

위의 Spinner 클래스 사용 예 :


with Spinner("just waiting a bit.. "):

        time.sleep(3)

https://github.com/Tagar/stuff/blob/master/spinner.py에 코드를 업로드했습니다.

참고 URL : https://stackoverflow.com/questions/4995733/how-to-create-a-spinning-command-line-cursor

반응형