Tkinter - 如果子窗口小部件获得焦点,则键绑定到框架将不起作用
Tkinter - key-binding to frame won't work if a child widget gets focus
我正在尝试为不同的帧编写一个具有不同键绑定的程序。
如果框架处于焦点状态,这会很好地工作,但如果另一个小部件处于焦点状态,则键绑定不起作用。
例如,在此试用代码中,如果没有小部件处于焦点,键绑定将起作用,但如果按钮处于焦点(以编程方式或通过使用 TAB wkey 使按钮聚焦),则框架上的键绑定不再有效。在按钮小部件上设置焦点后,将焦点设置在框架上没有帮助。
import tkinter as tk
class TestGUI(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
self.edit_text = tk.StringVar()
self.intro_label = tk.Label(self, text="Press button to say Hello")
self.hello_button = tk.Button(self, text='Say Hello (H)', command=self.press_button)
self.text_area = tk.Label(self, textvariable=self.edit_text, width=20, height=5)
self.intro_label.pack(padx=10, pady=5)
self.hello_button.pack(pady=5)
self.text_area.pack(padx=10, pady=(5, 10))
self.bind('<Key>', self.press_key)
self.hello_button.focus()
self.focus()
def press_button(self):
txt = self.edit_text.get()
txt += "Hello World!\n"
self.edit_text.set(txt)
def press_key(self, event):
key_pressed = event.char.lower()
if key_pressed == "h":
self.hello_button.invoke()
if __name__ == "__main__":
root = tk.Tk()
TestGUI(root).pack()
root.mainloop()
我知道如果我将绑定放在应用程序级别,按键绑定仍然有效:
parent.bind('<Key>', self.press_key)
但是,我想在应用程序的不同框架上使用不同的键绑定。有没有办法做到这一点,而不会在另一个小部件获得焦点时丢失键绑定?
抱歉,不,那不是 tkinter 的功能。绑定到 window 是一种特殊情况,允许 window 中的任何 child 对绑定做出反应。
听起来你想为每一帧使用不同的键?所以第一帧响应 'h',第二帧响应 's' 之类的?在那种情况下,您可以简单地将每个帧绑定到您想要的,而不是所有键。这也避免了需要第二种方法来调用按钮按下:
import tkinter as tk
class TestGUI(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
self.edit_text = tk.StringVar()
self.intro_label = tk.Label(self, text="Press button to say Hello")
self.hello_button = tk.Button(self, text='Say Hello (H)', command=self.press_button)
self.text_area = tk.Label(self, textvariable=self.edit_text, width=20, height=5)
self.intro_label.pack(padx=10, pady=5)
self.hello_button.pack(pady=5)
self.text_area.pack(padx=10, pady=(5, 10))
self.bind_all('<h>', self.press_button) # bind to the 'h' key
# ~ parent.bind('<h>', self.press_button) # alternative way
self.hello_button.focus()
self.focus()
def press_button(self, event=None):
txt = self.edit_text.get()
txt += "Hello World!\n"
self.edit_text.set(txt)
if __name__ == "__main__":
root = tk.Tk()
TestGUI(root).pack()
root.mainloop()
否则我想你可以做一个快速循环来绑定到框架中的所有 children。
def set_child_bind(widget, event, callback):
widget.bind(event, callback)
for child in widget.children.values():
set_child_bind(child, event, callback)
class TestGUI(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
# all the other stuff
set_child_bind(self, '<Key>', self.press_key)
或者您可以使用 FocusIn 事件获取 application-wide 绑定:
class TestGUI(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
# all the other stuff
self.bind('<FocusIn>', lambda e:self.bind_all('<Key>', self.press_key))
self.bind('<FocusOut>', lambda e:self.unbind_all('<Key>'))
我正在尝试为不同的帧编写一个具有不同键绑定的程序。
如果框架处于焦点状态,这会很好地工作,但如果另一个小部件处于焦点状态,则键绑定不起作用。
例如,在此试用代码中,如果没有小部件处于焦点,键绑定将起作用,但如果按钮处于焦点(以编程方式或通过使用 TAB wkey 使按钮聚焦),则框架上的键绑定不再有效。在按钮小部件上设置焦点后,将焦点设置在框架上没有帮助。
import tkinter as tk
class TestGUI(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
self.edit_text = tk.StringVar()
self.intro_label = tk.Label(self, text="Press button to say Hello")
self.hello_button = tk.Button(self, text='Say Hello (H)', command=self.press_button)
self.text_area = tk.Label(self, textvariable=self.edit_text, width=20, height=5)
self.intro_label.pack(padx=10, pady=5)
self.hello_button.pack(pady=5)
self.text_area.pack(padx=10, pady=(5, 10))
self.bind('<Key>', self.press_key)
self.hello_button.focus()
self.focus()
def press_button(self):
txt = self.edit_text.get()
txt += "Hello World!\n"
self.edit_text.set(txt)
def press_key(self, event):
key_pressed = event.char.lower()
if key_pressed == "h":
self.hello_button.invoke()
if __name__ == "__main__":
root = tk.Tk()
TestGUI(root).pack()
root.mainloop()
我知道如果我将绑定放在应用程序级别,按键绑定仍然有效:
parent.bind('<Key>', self.press_key)
但是,我想在应用程序的不同框架上使用不同的键绑定。有没有办法做到这一点,而不会在另一个小部件获得焦点时丢失键绑定?
抱歉,不,那不是 tkinter 的功能。绑定到 window 是一种特殊情况,允许 window 中的任何 child 对绑定做出反应。
听起来你想为每一帧使用不同的键?所以第一帧响应 'h',第二帧响应 's' 之类的?在那种情况下,您可以简单地将每个帧绑定到您想要的,而不是所有键。这也避免了需要第二种方法来调用按钮按下:
import tkinter as tk
class TestGUI(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
self.edit_text = tk.StringVar()
self.intro_label = tk.Label(self, text="Press button to say Hello")
self.hello_button = tk.Button(self, text='Say Hello (H)', command=self.press_button)
self.text_area = tk.Label(self, textvariable=self.edit_text, width=20, height=5)
self.intro_label.pack(padx=10, pady=5)
self.hello_button.pack(pady=5)
self.text_area.pack(padx=10, pady=(5, 10))
self.bind_all('<h>', self.press_button) # bind to the 'h' key
# ~ parent.bind('<h>', self.press_button) # alternative way
self.hello_button.focus()
self.focus()
def press_button(self, event=None):
txt = self.edit_text.get()
txt += "Hello World!\n"
self.edit_text.set(txt)
if __name__ == "__main__":
root = tk.Tk()
TestGUI(root).pack()
root.mainloop()
否则我想你可以做一个快速循环来绑定到框架中的所有 children。
def set_child_bind(widget, event, callback):
widget.bind(event, callback)
for child in widget.children.values():
set_child_bind(child, event, callback)
class TestGUI(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
# all the other stuff
set_child_bind(self, '<Key>', self.press_key)
或者您可以使用 FocusIn 事件获取 application-wide 绑定:
class TestGUI(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
# all the other stuff
self.bind('<FocusIn>', lambda e:self.bind_all('<Key>', self.press_key))
self.bind('<FocusOut>', lambda e:self.unbind_all('<Key>'))