Tkinter触摸屏虚拟键盘:解决打开后立即关闭的问题
Tkinter虚拟键盘打开后立即关闭的问题解决方法
我明白你遇到的问题啦——当点击输入框唤起虚拟键盘后,它立刻就消失了,这确实挺头疼的。咱们先说说原因,再一步步解决:
问题根源
当你给输入框绑定FocusIn事件打开键盘时,键盘窗口弹出后,窗口上的按钮会自动获取焦点,这就导致原来的输入框触发了FocusOut事件,直接触发关闭键盘的逻辑,于是键盘刚打开就被关掉了。
解决方案思路
我们需要给关闭键盘的逻辑加个“例外判断”:只有当焦点转移到虚拟键盘以外的控件时,才关闭键盘。同时还要修正代码里的小bug(比如select函数的参数错误)。
修改后的完整代码
import tkinter as tk import pyautogui # 全局变量跟踪大写状态和当前聚焦的输入控件 uppercase = False focused_entry = None window = None def select(entry, value): global uppercase if value == "Space": value = ' ' elif value == 'Enter': value = '\n' elif value == 'Tab': value = '\t' if value == "Backspace": if isinstance(entry, tk.Entry): entry.delete(len(entry.get())-1, 'end') else: # 处理Text控件的退格 entry.delete('end - 2c', 'end') elif value in ('Caps Lock', 'Shift'): uppercase = not uppercase # 切换大小写状态 else: if uppercase: value = value.upper() entry.insert('end', value) # 可选:如果需要模拟系统按键,这里用value而不是event pyautogui.press(value.lower() if value not in ['Space','Enter','Tab','Backspace'] else value) def create(root, entry): global window # 如果已有键盘窗口,先销毁 if window and window.winfo_exists(): window.destroy() alphabets = [ ['`','1','2','3','4','5','6','7','8','9','0','-','=','Backspace'], ['Tab','q','w','e','r','t','y','u','i','o','p','[',']','\\'], ['Caps Lock','a','s','d','f','g','h','j','k','l',';',"'",'Enter'], ['Shift','z','x','c','v','b','n','m',',','.','/','Shift'], ['Space'] ] window = tk.Toplevel(root) window.configure(background="cornflowerblue") window.geometry("+0+483") window.wm_attributes("-alpha", 0.7) # 给键盘窗口加个标识,方便后续判断 window.is_keyboard = True for y, row in enumerate(alphabets): x = 0 for text in row: # 设置按钮宽度和跨列 if text in ('Enter', 'Shift'): width = 18 columnspan = 2 elif text == 'Space': width = 124 columnspan = 16 elif text in ('Backspace', '\\', 'Tab', '`', 'Caps Lock'): width = 10 columnspan = 1 else: width = 4 columnspan = 1 # 创建按钮,确保不获取焦点 btn = tk.Button( window, text=text, width=width, command=lambda value=text: select(entry, value), padx=3, pady=3, bd=12, bg="black", fg="white", takefocus=False ) btn.grid(row=y, column=x, columnspan=columnspan) x += columnspan def remember_focus(event): global focused_entry focused_entry = event.widget # 唤起键盘 create(event.widget.master, focused_entry) def close_keyboard(event): global window # 获取当前焦点所在的控件 current_focus = event.widget.master.focus_get() # 如果焦点在键盘窗口内,不关闭键盘 if current_focus and getattr(current_focus.winfo_toplevel(), 'is_keyboard', False): return # 否则关闭键盘 if window and window.winfo_exists(): window.destroy() window = None if __name__ == '__main__': root = tk.Tk() root.title('Test Keyboard') root.grid_rowconfigure(1, weight=1) root.grid_rowconfigure(2, weight=1) root.grid_rowconfigure(3, weight=1) root.grid_columnconfigure(0, weight=1) label = tk.Label(root, text='Test Keyboard') label.grid(row=0, column=0, columnspan=2) entry1 = tk.Entry(root) entry1.grid(row=1, column=0, sticky='news') entry1.bind("<FocusIn>", remember_focus) entry1.bind("<FocusOut>", close_keyboard) entry2 = tk.Entry(root) entry2.grid(row=2, column=0, sticky='news') entry2.bind("<FocusIn>", remember_focus) entry2.bind("<FocusOut>", close_keyboard) text1 = tk.Text(root) text1.grid(row=3, column=0, sticky='news') text1.bind("<FocusIn>", remember_focus) text1.bind("<FocusOut>", close_keyboard) root.mainloop()
关键修改点说明
- 修正
select函数参数:原来的函数多了一个event参数,但调用时并没有传递,导致运行报错,现在已经移除多余参数。 - 键盘窗口标识:给键盘窗口添加
is_keyboard = True属性,方便在FocusOut回调中判断焦点是否在键盘内。 - 智能关闭逻辑:在
close_keyboard函数中,检查当前焦点的顶层窗口是否是键盘窗口,如果是就不执行关闭操作,避免误关闭。 - 控件布局优化:添加了
grid_rowconfigure和grid_columnconfigure,让输入控件能自适应窗口大小,更适合触摸屏场景。
这样修改后,当点击输入框唤起键盘时,即使焦点转移到键盘按钮上,也不会关闭键盘;只有当你点击键盘以外的区域(比如另一个输入框),才会关闭当前键盘并唤起对应输入框的键盘(或者直接关闭)。
内容的提问来源于stack exchange,提问作者jjy
相关产品推荐
相关产品推荐

