Python 将 Shift 键按下绑定到命令

Python bind a Shift key press to a command

我想在按下 shift 时激活一个命令,在 shift 释放时激活另一个命令。我需要像 ShiftPress 或 ShiftRelease 这样的东西。有任何想法吗? btn.bind('', lambda event, a=a: cmd(a))

似乎你想要的东西单独使用 Tkinter 是不可能的

current docs and the old docs aren't very helpful about what all events are possible to bind, but we can find more detail in the source code.

这给了我们一些测试:

import tkinter as tk


class App(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.pack()

        self.entry = tk.Entry()
        self.entry.pack()

        self.entry.bind(
            "<Key>", lambda e: print(f"<Key> {e.char!r}")
        )
        self.entry.bind(
            "<Shift-KeyPress>", lambda e: print(f"<Shift-KeyPress> {e.char!r}")
        )
        self.entry.bind(
            "<Shift-KeyRelease>", lambda e: print(f"<Shift-KeyRelease> {e.char!r}")
        )


if __name__ == "__main__":
    root = tk.Tk()
    app = App(root)
    app.mainloop()

运行这个然后点击进入输入框。当您按下并释放 shift 键时,这只会打印 <Shift-KeyPress> ''

不幸的是,因为 Shift 是一个“修饰符”键,它在被按下时不会触发释放事件,只会触发按下事件。

更新

通过更多的实验,我们可以做得更好:

import tkinter as tk


class App(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.pack()

        self.entry = tk.Entry()
        self.entry.pack()

        self.entry.bind(
            "<KeyRelease>", lambda e: print(repr(e))
        )


if __name__ == "__main__":
    root = tk.Tk()
    app = App(root)
    app.mainloop()

运行这个然后点击进入输入框。现在我们可以看到打印:

<KeyRelease event keysym=Shift_L keycode=939587838 x=126 y=14>
<KeyRelease event keysym=Shift_R keycode=1006696702 x=126 y=14>

所以看起来 可以使用 tkinter 检测 Shift 键的按键释放事件。

我们现在可以将其组合成一个更简洁的解决方案:

import tkinter as tk


SHIFT_KEYS = {"Shift_L", "Shift_R"}


def shift_press(event):
    if event.keysym in SHIFT_KEYS:
        print("Shift press")


def shift_release(event):
    if event.keysym in SHIFT_KEYS:
        print("Shift release")


class App(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.pack()

        self.entry = tk.Entry()
        self.entry.pack()

        self.entry.bind("<KeyPress>", shift_press)
        self.entry.bind("<KeyRelease>", shift_release)


if __name__ == "__main__":
    root = tk.Tk()
    app = App(root)
    app.mainloop()

我不知道 tkinter,但我想你可以通过某种方式使输入框不可见,或者找到一些其他可以捕获键盘事件的元素。

更新 2

在@Delrius Euphoria 的评论帮助下,事实证明我们实际上可以做到这一点:

import tkinter as tk


def shift_press(event):
    print("Shift press")


def shift_release(event):
    print("Shift release")


class App(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.pack()

        self.entry = tk.Entry()
        self.entry.pack()

        self.entry.bind("<KeyPress-Shift_L>", shift_press)
        self.entry.bind("<KeyPress-Shift_R>", shift_press)
        self.entry.bind("<KeyRelease-Shift_L>", shift_release)
        self.entry.bind("<KeyRelease-Shift_R>", shift_release)


if __name__ == "__main__":
    root = tk.Tk()
    app = App(root)
    app.mainloop()

事后看来,我们现在可以 Google 寻找答案,例如这里 https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/key-names.html 给出了一个键名列表,其中包括 Shift_LShift_R.