使用 Pynput 按键暂停和取消暂停 TQDM 进度条

Pause and Unpause TQDM Progress Bar Using Pynput Key Press

我正在创建一个使用 TQDM 进度条库的小程序,我想在其中按 space 来“暂停”和“取消暂停”进度条。进度条应该每秒更新一次,当输入的时间完成时 运行 100%。请查看我在下面所做的尝试,当 运行 时,进度条永远不会自行更新。感谢您的反馈。

from tqdm import tqdm
from pynput import keyboard

class TimerTimer:
    def __init__(self, fileLoc) -> None:
        self.timer_list = self.get_timer_list(fileLoc)
        self.timer_length = len(self.timer_list)
        self.kb_listener = None
        self.init_val = 0
        self.wait = False

    def on_press_or_release(self, key):
        if key == keyboard.Key.esc:
            print("Exiting")
            exit()
        if key == keyboard.Key.space:
            self.wait = not self.wait
            printStr = "\nPaused...\n" if self.wait else "\nResumed!"
            print(printStr)
            return False

    def timer_with_progress(self, time_limit, name):
        print("{} for {} seconds:".format(name, time_limit))
        t = tqdm(total=time_limit, desc=name, ncols=100, initial=self.init_val)

        #for i in tqdm(range(time_limit), desc=name, ncols=100, initial=self.init_val):
        for i in range(time_limit):
            # sleep(1)
            # The event listener will be running in this block
            with keyboard.Events() as events:
                # Block at most one second
                event = events.get(1.0)
                if event is None:
                    break
                elif event.key == keyboard.Key.esc:
                    print("Exiting")
                    exit()
                elif event.key == keyboard.Key.space:
                    self.wait = not self.wait
                    printStr = "\nPaused...\n" if self.wait else "\nResumed!"
                    print(printStr)
                else:
                    break

            t.update()
            # t.refresh()
        t.close()

    def run(self):
        for index in self.timer_list:
            timer_cmd_list = ["self.timer_with_progress(5, 'Rest')",
                            "self.timer_with_progress(self.timer_list[index]['durationSeconds'], self.timer_list[index]['timerName'])"]
            for cmd in timer_cmd_list:
                if not self.wait:
                    exec(cmd)
                else:
                    if self.kb_listener is None:
                        self.kb_listener = keyboard.Listener(on_press = self.on_press_or_release) # , on_release = self.on_press_or_release)
                        self.kb_listener.start()
                    self.kb_listener.join() # Waits until the key is pressed again
                    self.wait = not self.wait # Once the button is pressed again, it changes the flag


if __name__=="__main__":
    tt = TimerTimer(filename)
    tt.run()

所以经过一些研究,我发现 progressbar2 似乎实现了一个更好的中断来完成我的目标。见下文:

import progressbar
from pynput import keyboard
from time import sleep

class TimerTimer:
    def __init__(self, fileLoc) -> None:
        self.timer_list = self.get_timer_list(fileLoc)
        self.timer_length = len(self.timer_list)
        self.wait = False

    def on_press(self, key):
        pass

    def on_release(self, key):
        if key == keyboard.Key.space:
            self.wait = not self.wait
            printStr = "Paused..." if self.wait else "\nResuming..."
            print(printStr)
        elif key == keyboard.Key.esc:
            print("Exiting")
            exit()

    def timer_with_progress(self, time_limit: int, name: str, iter:int=1) -> None:
        """Function that runs the progressbar2 progress bar.

        Keyword arguments:
        time_limit -- (int) The time limit (in seconds) for the progress bar.
        name -- (string) The Name of the progress bar, or the brief description.
        iter -- (int) The iteration time in seconds.  (default 1)
        """
        print("{} for {} seconds:".format(color.BOLD + name +color.END, time_limit))
        bar = progressbar.ProgressBar(max_value=time_limit)
        i = 0
        # Adding keyboard listener
        listener = keyboard.Listener(on_press=self.on_press, on_release=self.on_release)
        listener.start()
        while i <= time_limit:
            sleep(iter)
            if not self.wait:
                bar.update(i)
                i += iter
        bar.finish()

    def run(self):
        for index in self.timer_list:
            self.timer_with_progress(5, 'Rest')
            self.timer_with_progress(self.timer_list[index]['durationSeconds'], self.timer_list[index]['timerName'])


if __name__=="__main__":
    tt = TimerTimer(filename)
    tt.run()