在没有焦点的情况下监视 tkinter 中的按键

2024-01-08

我正在使用 tkinter 在 Python 中编写一个小型计时模块。在这方面,我想全局监控何时按下退出键来停止计时。

不幸的是,tkinters“.bind”和“.bind_all”函数仅在窗口处于焦点时才拾取击键。

我已经研究了其他几个用于记录击键的解决方案,包括包“keyboard”和“pynput”,但是这些包需要运行一个 while 循环,这使得 tkinter GUI 冻结并停止工作。

我找到了这个线程,但它对于具体展示如何完成它并不是很有帮助:无需在 tkinter 上绘制画布或框架即可检测按键 https://stackoverflow.com/questions/45017956/detect-keypress-without-drawing-canvas-or-frame-on-tkinter

我尝试过一些不同的选择

选项 1:使用 tkinter 循环功能,但按下按键时不注册

import keyboard
def _check_esc_pressed(self):
    if self.run_active and keyboard.press('esc'):
        self.Lap()
        self.Stop()
    self.after(50, self._check_esc_pressed())

选项 2:冻结 tkinter 客户端

import keyboard  
def _check_esc_pressed(self):
    while True:  
        if keyboard.is_pressed('esc'): 
            self.Lap()
            self.Stop()
            break  
        else:
            pass

选项 3:冻结 tkinter 客户端

from pynput.keyboard import Key, Listener
def on_release(self, key):
    if key == Key.esc:
        self.Lap()
        self.Stop()
        # Stop listener
        return False

def _check_esc_pressed(self):
    def on_press(key):
        pass
    with Listener(
            on_press=on_press,
            on_release=on_release) as listener:
        listener.join()

我预计按 escape 将终止“_check_esc_pressed”功能,注册一圈并停止计时器。仅当运行处于活动状态时才应处理逃逸检查


如果您仍然需要答案,或者其他人发现这有用......

答案可能就在我们看不到的代码中——通过将应用程序的逻辑放在另一个线程中,它允许 tkinter 在不冻结的情况下执行其操作。

下面的代码遵循您的(稍作修改的)选项2:

import queue
import keyboard  
import threading
import time
import tkinter as tk

def app_main_loop(my_label):
    # Create another thread that monitors the keyboard
    input_queue = queue.Queue()
    kb_input_thread = threading.Thread(target=_check_esc_pressed, args=(input_queue,))
    kb_input_thread.daemon = True
    kb_input_thread.start()
    
    # Main logic loop
    run_active = True
    while True:
        if not input_queue.empty():
            if (run_active) and (input_queue.get() == "esc"):
                run_active = False
                Lap(my_label)
                Stop()
        time.sleep(0.1)  # seconds

def _check_esc_pressed(input_queue):
    while True:
        if keyboard.is_pressed('esc'):
            input_queue.put("esc")
        time.sleep(0.1) # seconds

def Lap(my_label):
    my_label.configure(text = "Lap")

def Stop():
    print("Stopped")

if __name__ == "__main__":
    # Create the ui
    root = tk.Tk()
    root.attributes("-fullscreen", True)
    my_label = tk.Label(root, text="Hello World!")
    my_label.pack()
    
    # Run the app's main logic loop in a different thread
    main_loop_thread = threading.Thread(target=app_main_loop, args=(my_label, ))
    main_loop_thread.daemon = True
    main_loop_thread.start()
    
    # Run the UI's main loop
    root.mainloop()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在没有焦点的情况下监视 tkinter 中的按键 的相关文章

随机推荐