我正在开发一个程序,它有一个我用Tkinter创建的虚拟键盘。启用了键盘的页面具有用户需要输入数据的条目小部件。我使用pyautogui
作为虚拟键盘的一部分来模拟键盘按下,但我的问题是当用户按下键盘上的任何按钮时聚焦的小部件。由于按键时每个键盘按钮都是ttk.Button
,因此按钮具有焦点,而不是他们选择的条目小部件,他们试图将数据放入。
就这样,我现在有了运行按键的方法,在按键之前调用特定小部件成为焦点。这是我现在的代码:
import tkinter as tk
from tkinter import ttk
import pyautogui
def drawKeyboard(parent):
keyboardFrame = tk.Frame(parent)
keyboardFrame.pack()
keys = [
[ ("Alpha Keys"),
[ ('q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'),
(' ', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'),
('capslock', 'z', 'x', 'c', 'v', 'b', 'n', 'm'),
('delete', 'backspace', 'home', 'end')
]
],
[ ("Numeric Keys"),
[ ('7', '8', '9'),
('4', '5', '6'),
('1', '2', '3'),
(' ', '0', ' ')
]
]
]
for key_section in keys:
sect_vals = key_section[1]
sect_frame = tk.Frame(keyboardFrame)
sect_frame.pack(side = 'left', expand = 'yes', fill = 'both', padx = 10, pady = 10, ipadx = 10, ipady = 10)
for key_group in sect_vals:
group_frame = tk.Frame(sect_frame)
group_frame.pack(side = 'top', expand = 'yes', fill = 'both')
for key in key_group:
key = key.capitalize()
if len(key) <= 1:
key_button = ttk.Button(group_frame, text = key, width = 4)
else:
key_button = ttk.Button(group_frame, text = key.center(5, ' '))
if ' ' in key:
key_button['state'] = 'disable'
key_button['command'] = lambda q=key.lower(): key_command(q)
key_button.pack(side = 'left', fill = 'both', expand = 'yes')
def key_command(event):
entry1.focus()
pyautogui.press(event)
return
root = tk.Tk()
entry1 = tk.Entry(root)
entry1.pack()
entry2 = tk.Entry(root)
entry2.pack()
drawKeyboard(root)
root.mainloop()
如果我想将数据输入entry1.focus()
,显然手动调用entry2
对我没有好处。如果我想将数据放入entry2.focus()
,则调用entry1
无效。那么每次按下我的一个按钮时,有没有办法检查哪个Entry Widget最后有焦点?
我需要检查具体的输入小部件,因为最终屏幕也会有一些单选按钮等。谢谢你的时间
编辑:我快速更改了代码,交换了Shift
密钥的Capslock
密钥。我意识到我的代码工作方式Shift实际上永远不会工作,因为你无法完全按住它并按下另一个按钮。
答案 0 :(得分:3)
您可以将属性takefocus
设置为False
,以防止按钮获得焦点。这有一个不幸的副作用,就是无法使用键盘遍历按钮(这可能没问题,因为你处于非键盘状态)
...
key_button = ttk.Button(..., takefocus=False)
...
def key_command(event):
entry = root.focus_get()
entry.insert("end", event)
pyautogui.press(event)
return
另一个解决方案是在<FocusIn>
事件上添加一个绑定,您可以在其中将窗口小部件保存在全局变量中。
def key_command(event):
focused_entry.insert("end", event)
pyautogui.press(event)
return
def remember_focus(event):
global focused_entry
focused_entry = event.widget
entry1.bind("<FocusIn>", remember_focus)
entry2.bind("<FocusIn>", remember_focus)
如果您有许多条目小部件,则可以在Entry
类上进行类绑定:
root.bind_class("Entry", "<FocusIn>", remember_focus)
答案 1 :(得分:0)
您好,您会发现两种有用的方法,这些方法在本文中有描述:
How do you check if a widget has focus in Tkinter?
将输入框绑定到Enter键。当按下enter时,调用处理函数并将焦点存储在一个全局可访问的变量中,例如self.entry_focus,以防你构建一个类或只是在模块范围级别的脚本开头声明的entry_focus。处理事件时,您可以通过访问传递给处理程序的事件对象来获取信息调用哪个窗口小部件。使用event.widget和root.focus_get方法。
将Enter绑定到根项目。然后使用focus_get方法检查每次按下输入时焦点的位置,无论鼠标光标或焦点在哪里。
请参阅上面帖子中的代码。一切都会很清楚。
祝你好运!