Tkinter多窗口屏幕键盘输入时Entry组件不显示文本问题
Tkinter Entry绑定textvariable后不显示文本问题排查
问题现象
两个Python脚本协作实现GUI:主脚本main.py实现Tkinter主窗口,点击窗口上的「Cerca」按钮会调用cerca.py中的方法,弹出屏幕键盘二级窗口。故障表现为:变量exp赋值更新后,绑定了textvariable的Entry输入框始终不显示对应文本。
附原始代码
第一个脚本main.py:
import tkinter from tkinter import messagebox from settings import Settings from buttons.cerca import Cerca class TIICP(): def event_test(): return messagebox.showinfo('Test', 'This is a test!') def cerca(): Cerca.start() if __name__ == '__main__': window = tkinter.Tk() window.title(Settings.get_setting_data("title")) window_width = Settings.get_setting_data("width") window_height = Settings.get_setting_data("height") screen_width = window.winfo_screenwidth() screen_height = window.winfo_screenheight() center_x = int(screen_width / 2 - window_width / 2) center_y = int(screen_height / 2 - window_height / 2) window.geometry(f'{window_width}x{window_height}+{center_x}+{center_y}') window.configure(bg='black') # Esplora esplora_button = tkinter.Button( window, text='Esplora', command=TIICP.event_test ) esplora_button.pack( ipadx=5, ipady=5, expand=True ) # Cerca cerca_button = tkinter.Button( window, text='Cerca', command=TIICP.cerca ) cerca_button.pack( ipadx=5, ipady=5, expand=True ) # Radio radio_button = tkinter.Button( window, text='Radio', command=TIICP.event_test ) radio_button.pack( ipadx=5, ipady=5, expand=True ) window.mainloop()
第二个脚本cerca.py:
import tkinter from settings import Settings from tkinter import ttk exp = " " class Cerca: def start(): cerca_window = tkinter.Tk() cerca_window.title(Settings.get_setting_data("title")) def press(num): global exp exp = exp + str(num) equation.set(exp) def clear(): global exp exp = " " equation.set(exp) def action(): exp = " Next Line : " equation.set(exp) def Tab(): exp = " TAB : " equation.set(exp) window_width = Settings.get_setting_data("width") window_height = Settings.get_setting_data("height") screen_width = cerca_window.winfo_screenwidth() screen_height = cerca_window.winfo_screenheight() center_x = int(screen_width / 2 - window_width / 2) center_y = int(screen_height / 2 - window_height / 2) cerca_window.geometry(f'{window_width}x{window_height}+{center_x}+{center_y}') cerca_window.configure(bg='green') equation = tkinter.StringVar() Dis_entry = ttk.Entry(cerca_window, state='readonly', textvariable=equation) Dis_entry.grid(rowspan=1, columnspan=100, ipadx=1000, ipady=20) q = ttk.Button(cerca_window, text='Q', width=6, command=lambda: press('Q')) q.grid(row=1, column=0, ipadx=6, ipady=10) w = ttk.Button(cerca_window, text='W', width=6, command=lambda: press('W')) w.grid(row=1, column=1, ipadx=6, ipady=10) E = ttk.Button(cerca_window, text='E', width=6, command=lambda: press('E')) E.grid(row=1, column=2, ipadx=6, ipady=10) R = ttk.Button(cerca_window, text='R', width=6, command=lambda: press('R')) R.grid(row=1, column=3, ipadx=6, ipady=10) T = ttk.Button(cerca_window, text='T', width=6, command=lambda: press('T')) T.grid(row=1, column=4, ipadx=6, ipady=10) Y = ttk.Button(cerca_window, text='Y', width=6, command=lambda: press('Y')) Y.grid(row=1, column=5, ipadx=6, ipady=10) U = ttk.Button(cerca_window, text='U', width=6, command=lambda: press('U')) U.grid(row=1, column=6, ipadx=6, ipady=10) I = ttk.Button(cerca_window, text='I', width=6, command=lambda: press('I')) I.grid(row=1, column=7, ipadx=6, ipady=10) O = ttk.Button(cerca_window, text='O', width=6, command=lambda: press('O')) O.grid(row=1, column=8, ipadx=6, ipady=10) P = ttk.Button(cerca_window, text='P', width=6, command=lambda: press('P')) P.grid(row=1, column=9, ipadx=6, ipady=10) cur = ttk.Button(cerca_window, text='{', width=6, command=lambda: press('{')) cur.grid(row=1, column=10, ipadx=6, ipady=10) cur_c = ttk.Button(cerca_window, text='}', width=6, command=lambda: press('}')) cur_c.grid(row=1, column=11, ipadx=6, ipady=10) back_slash = ttk.Button(cerca_window, text='\\', width=6, command=lambda: press('\\')) back_slash.grid(row=1, column=12, ipadx=6, ipady=10) clear = ttk.Button(cerca_window, text='Clear', width=6, command=clear) clear.grid(row=1, column=13, ipadx=20, ipady=10) # Second Line Button A = ttk.Button(cerca_window, text='A', width=6, command=lambda: press('A')) A.grid(row=2, column=0, ipadx=6, ipady=10) S = ttk.Button(cerca_window, text='S', width=6, command=lambda: press('S')) S.grid(row=2, column=1, ipadx=6, ipady=10) D = ttk.Button(cerca_window, text='D', width=6, command=lambda: press('D')) D.grid(row=2, column=2, ipadx=6, ipady=10) F = ttk.Button(cerca_window, text='F', width=6, command=lambda: press('F')) F.grid(row=2, column=3, ipadx=6, ipady=10) G = ttk.Button(cerca_window, text='G', width=6, command=lambda: press('G')) G.grid(row=2, column=4, ipadx=6, ipady=10) H = ttk.Button(cerca_window, text='H', width=6, command=lambda: press('H')) H.grid(row=2, column=5, ipadx=6, ipady=10) J = ttk.Button(cerca_window, text='J', width=6, command=lambda: press('J')) J.grid(row=2, column=6, ipadx=6, ipady=10) K = ttk.Button(cerca_window, text='K', width=6, command=lambda: press('K')) K.grid(row=2, column=7, ipadx=6, ipady=10) L = ttk.Button(cerca_window, text='L', width=6, command=lambda: press('L')) L.grid(row=2, column=8, ipadx=6, ipady=10) semi_co = ttk.Button(cerca_window, text=';', width=6, command=lambda: press(';')) semi_co.grid(row=2, column=9, ipadx=6, ipady=10) d_colon = ttk.Button(cerca_window, text='"', width=6, command=lambda: press('"')) d_colon.grid(row=2, column=10, ipadx=6, ipady=10) enter = ttk.Button(cerca_window, text='Enter', width=6, command=action) enter.grid(row=2, columnspan=75, ipadx=85, ipady=10) # third line Button Z = ttk.Button(cerca_window, text='Z', width=6, command=lambda: press('Z')) Z.grid(row=3, column=0, ipadx=6, ipady=10) X = ttk.Button(cerca_window, text='X', width=6, command=lambda: press('X')) X.grid(row=3, column=1, ipadx=6, ipady=10) C = ttk.Button(cerca_window, text='C', width=6, command=lambda: press('C')) C.grid(row=3, column=2, ipadx=6, ipady=10) V = ttk.Button(cerca_window, text='V', width=6, command=lambda: press('V')) V.grid(row=3, column=3, ipadx=6, ipady=10) B = ttk.Button(cerca_window, text='B', width=6, command=lambda: press('B')) B.grid(row=3, column=4, ipadx=6, ipady=10) N = ttk.Button(cerca_window, text='N', width=6, command=lambda: press('N')) N.grid(row=3, column=5, ipadx=6, ipady=10) M = ttk.Button(cerca_window, text='M', width=6, command=lambda: press('M')) M.grid(row=3, column=6, ipadx=6, ipady=10) left = ttk.Button(cerca_window, text='<', width=6, command=lambda: press('<')) left.grid(row=3, column=7, ipadx=6, ipady=10) right = ttk.Button(cerca_window, text='>', width=6, command=lambda: press('>')) right.grid(row=3, column=8, ipadx=6, ipady=10) slas = ttk.Button(cerca_window, text='/', width=6, command=lambda: press('/')) slas.grid(row=3, column=9, ipadx=6, ipady=10) q_mark = ttk.Button(cerca_window, text='?', width=6, command=lambda: press('?')) q_mark.grid(row=3, column=10, ipadx=6, ipady=10) coma = ttk.Button(cerca_window, text=',', width=6, command=lambda: press(',')) coma.grid(row=3, column=11, ipadx=6, ipady=10) dot = ttk.Button(cerca_window, text='.', width=6, command=lambda: press('.')) dot.grid(row=3, column=12, ipadx=6, ipady=10) shift = ttk.Button(cerca_window, text='Shift', width=6, command=lambda: press('Shift')) shift.grid(row=3, column=13, ipadx=20, ipady=10) # Fourth Line Button ctrl = ttk.Button(cerca_window, text='Ctrl', width=6, command=lambda: press('Ctrl')) ctrl.grid(row=4, column=0, ipadx=6, ipady=10) Fn = ttk.Button(cerca_window, text='Fn', width=6, command=lambda: press('Fn')) Fn.grid(row=4, column=1, ipadx=6, ipady=10) window = ttk.Button(cerca_window, text='Window', width=6, command=lambda: press('Window')) window.grid(row=4, column=2, ipadx=6, ipady=10) Alt = ttk.Button(cerca_window, text='Alt', width=6, command=lambda: press('Alt')) Alt.grid(row=4, column=3, ipadx=6, ipady=10) space = ttk.Button(cerca_window, text='Space', width=6, command=lambda: press(' ')) space.grid(row=4, columnspan=14, ipadx=160, ipady=10) Alt_gr = ttk.Button(cerca_window, text='Alt Gr', width=6, command=lambda: press('Alt Gr')) Alt_gr.grid(row=4, column=10, ipadx=6, ipady=10) open_b = ttk.Button(cerca_window, text='(', width=6, command=lambda: press('(')) open_b.grid(row=4, column=11, ipadx=6, ipady=10) close_b = ttk.Button(cerca_window, text=')', width=6, command=lambda: press(')')) close_b.grid(row=4, column=12, ipadx=6, ipady=10) tap = ttk.Button(cerca_window, text='Tab', width=6, command=Tab) tap.grid(row=4, column=13, ipadx=20, ipady=10) cerca_window.mainloop()
故障根因
- 核心错误:多Tk根窗口实例冲突。Tkinter程序全局只能存在一个
Tk()根窗口实例,主窗口已经创建Tk()实例的前提下,弹窗又新建了第二个Tk()实例,两个实例有独立的上下文和事件循环,会导致StringVar与组件的绑定关系失效,UI无法正常更新。 - 局部变量遮蔽全局变量。
action()和Tab()两个函数内给exp赋值时,没有加global exp声明,函数内部的exp是独立局部变量,不会修改全局的exp值,点击Enter、Tab按钮时也无法按预期更新内容。 - 重复事件循环。第二个窗口单独调用
mainloop()会和主窗口的事件循环产生阻塞冲突,进一步加剧UI更新异常。
修复方案
- 将弹窗的
tkinter.Tk()替换为tkinter.Toplevel(),Toplevel是Tkinter标准的二级弹窗组件,共享主窗口的事件循环和上下文,不会产生变量绑定冲突。 - 在
action()、Tab()函数内开头添加global exp声明,确保修改的是全局exp变量。 - 删除弹窗的
cerca_window.mainloop()调用,所有窗口的事件统一由主窗口的mainloop()处理。
修正后cerca.py核心代码片段
import tkinter from settings import Settings from tkinter import ttk exp = " " class Cerca: def start(): # 替换Tk()为Toplevel() cerca_window = tkinter.Toplevel() cerca_window.title(Settings.get_setting_data("title")) def press(num): global exp exp = exp + str(num) equation.set(exp) def clear(): global exp exp = " " equation.set(exp) def action(): # 添加global声明 global exp exp = " Next Line : " equation.set(exp) def Tab(): # 添加global声明 global exp exp = " TAB : " equation.set(exp) # 中间布局代码和原代码保持一致 # ... # 删除cerca_window.mainloop()调用
修改完成后重新运行,点击键盘按钮即可正常在Entry组件中显示输入内容。
内容的提问来源于stack exchange,提问作者Rekcah
相关产品推荐
相关产品推荐

