You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tkinter二次打开子窗口后焦点切换报错问题求助

问题分析与解决方案

核心问题原因

  1. 全局列表未清空:win2_lstHandle作为全局变量,每次打开子窗口都会追加输入框控件引用。关闭子窗口后,旧控件的引用仍留在列表中,再次打开子窗口时,焦点切换函数会尝试访问已销毁的控件,触发_tkinter.TclError。
  2. 错误使用Tk()创建子窗口:Tkinter程序应仅存在一个主Tk实例,用Tk()创建子窗口会生成独立的Tcl解释器,引发焦点管理混乱,导致跨窗口切换焦点的问题。
  3. 焦点切换依赖全局状态:子窗口的焦点切换逻辑依赖全局列表,多个子窗口实例共享同一列表,导致焦点跳转时遍历所有历史控件。

修正后的代码

from tkinter import *  
from tkinter import ttk  


def o_downKey(event):
    o_handle = event.widget.focus_get()
    o_lstHandle[(o_lstHandle.index(o_handle) + 1)%len(o_lstHandle)].focus()

def o_upKey(event):
    o_handle = event.widget.focus_get()
    o_lstHandle[(o_lstHandle.index(o_handle) - 1)%len(o_lstHandle)].focus()


def new_win():
    # 用Toplevel创建子窗口,依附于主窗口
    win2 = Toplevel()
    win2.title('Расчет квадратуры')
    win2.geometry('300x185+600+190')
    win2.resizable(0,0)

    # 子窗口控件列表设为局部变量,每个窗口独立维护
    win2_lstHandle = []

    def win2_downKey(event):
        win2_handle = event.widget.focus_get()
        win2_lstHandle[(win2_lstHandle.index(win2_handle) + 1)%len(win2_lstHandle)].focus()

    def win2_upKey(event):
        win2_handle = event.widget.focus_get()
        win2_lstHandle[(win2_lstHandle.index(win2_handle) - 1)%len(win2_lstHandle)].focus()

    lbl_up = Label(win2, text = 'win2 label', font = 'normal, 13')
    lbl_up.place(x=5, y=7)
    lbl_kk = Label(win2, text = 'win2 labl', font = 'normal, 13')    
    lbl_kk.place(x=5, y=34)

    ent_up = Entry(win2, font = 'normal, 13',borderwidth=3, relief="ridge")
    win2_lstHandle.append(ent_up)
    ent_up.bind('<Left>', win2_downKey)
    ent_up.bind('<Right>', win2_upKey)
    ent_up.bind('<Return>', win2_upKey)
    ent_up.place(width=85, x=127, y=6)

    ent_kk = Entry(win2, width = 18, font = 'normal, 13',borderwidth=3, relief="ridge")
    win2_lstHandle.append(ent_kk)
    ent_kk.bind('<Left>', win2_downKey)
    ent_kk.bind('<Right>', win2_upKey)
    ent_kk.bind('<Return>', win2_upKey)
    ent_kk.place(x=127, y=34)

    ent_up1 = Entry(win2, font = 'normal, 13',borderwidth=3, relief="ridge")
    win2_lstHandle.append(ent_up1)
    ent_up1.bind('<Left>', win2_downKey)
    ent_up1.bind('<Right>', win2_upKey)
    ent_up1.bind('<Return>', win2_upKey)    
    ent_up1.place(width=85, x=212, y=6)

    # 关闭子窗口时清空列表,避免残留引用
    def on_close():
        win2_lstHandle.clear()
        win2.destroy()
    win2.protocol("WM_DELETE_WINDOW", on_close)


win = Tk()
win.title("CFS")  
win.geometry('500x310+500+200') 
win.resizable(0, 0)

o_lstHandle = []

mainmenu = Menu(win) 
win.config(menu=mainmenu)

filemenu = Menu(mainmenu, tearoff=0)
filemenu.add_command(label="1", command = new_win)

filemenu_1 = Menu(mainmenu, tearoff=0)

filemenu_1.add_command(label="1")
filemenu_1.add_command(label="2")
filemenu_1.add_command(label="3")

mainmenu.add_cascade(label="command", menu=filemenu)
mainmenu.add_cascade(label = 'command 2', menu = filemenu_1)



frame = ttk.Frame(win, relief="groove", borderwidth = 0)
frame.pack(expand=1, fill='both')

tab_control = ttk.Notebook(frame)

tab1 = ttk.Frame(relief="groove", borderwidth = 1) 
tab3 = ttk.Frame(relief="groove", borderwidth = 1)
tab4 = ttk.Frame(relief="groove", borderwidth = 1)

s = ttk.Style()
s.configure('TNotebook.Tab', font='normal, 10')


tab_control.add(tab1, text='tab1')
tab_control.add(tab3, text='tab2')
tab_control.add(tab4, text='tab3')


tab_control.pack(expand=1, fill='both', padx=1,pady=1) 

o_ent1 = Entry(tab1, width=8, font = 'normal, 13',borderwidth=3, relief="ridge")
o_lstHandle.append(o_ent1)
o_ent1.bind('<Down>', o_downKey)
o_ent1.bind('<Up>', o_upKey)
o_ent1.bind('<Return>', o_downKey)
o_ent1.place(x=115,y=15)

o_ent2 = Entry(tab1, width=8, font = 'normal, 13',borderwidth=3, relief="ridge")
o_lstHandle.append(o_ent2)
o_ent2.bind('<Down>', o_downKey)
o_ent2.bind('<Up>', o_upKey)
o_ent2.bind('<Return>', o_downKey)
o_ent2.place(x=115,y=41)

o_ent3 = Entry(tab1, width=8, font = 'normal, 13',borderwidth=3, relief="ridge")
o_lstHandle.append(o_ent3)
o_ent3.bind('<Down>', o_downKey)
o_ent3.bind('<Up>', o_upKey)
o_ent3.bind('<Return>', o_downKey)
o_ent3.place(x=115,y=67)

o_ent4 = Entry(tab1, width=8, font = 'normal, 13',borderwidth=3, relief="ridge")
o_lstHandle.append(o_ent4)
o_ent4.bind('<Down>', o_downKey)
o_ent4.bind('<Up>', o_upKey)
o_ent4.bind('<Return>', o_downKey)
o_ent4.place(x=115,y=93) 

o_ent5 = Entry(tab1, width=8, font = 'normal, 13',borderwidth=3, relief="ridge")
o_lstHandle.append(o_ent5)
o_ent5.bind('<Down>', o_downKey)
o_ent5.bind('<Up>', o_upKey)
o_ent5.bind('<Return>', o_downKey)
o_ent5.place(x=115,y=119)

o_ent6 = Entry(tab1, width=8, font = 'normal, 13',borderwidth=3, relief="ridge")
o_lstHandle.append(o_ent6)
o_ent6.bind('<Down>', o_downKey)
o_ent6.bind('<Up>', o_upKey)
o_ent6.bind('<Return>', o_downKey)
o_ent6.place(x=115,y=145)


o_lb1 = Label(tab1, text='label 1', font = 'normal, 13')
o_lb1.place(x=15,y=15)

o_lb2 = Label(tab1, text='label 2', font = 'normal, 13')
o_lb2.place(x=15,y=41)

o_lb3 = Label(tab1, text='label 3', font = 'normal, 13')
o_lb3.place(x=15,y=67)

o_lb4 = Label(tab1, text='label 4', font = 'normal, 13')
o_lb4.place(x=15,y=93)

o_lb5 = Label(tab1, text='label 5', font = 'normal, 13')
o_lb5.place(x=15,y=119)

o_lb6 = Label(tab1, text='label 6', font = 'normal, 13')
o_lb6.place(x=15,y=145)


otkr_knop = Button(tab1, text = 'Button 1', font = 'normal, 13', borderwidth=3, relief="ridge")
otkr_knop.place(x=10,y=230)

o_ochist = Button(tab1, text = 'Button 2', font = 'normal, 13', borderwidth=3, relief="ridge")
o_ochist.place(x=110,y=230)


canvas = Canvas(tab1, bg="white", width=280, height=258,   relief=GROOVE, bd=3)
canvas.pack(anchor = SE)

tpk1 = Label(tab1, text = 'text"', font  = 'Arial 9 bold roman', fg='blue')
tpk1.place(x=402,y=264)

mytex = canvas.create_text(150, 135, text="")


win.mainloop()

关键修正点

  • 替换Tk()为Toplevel():子窗口依附于主窗口,共享同一个Tcl解释器,解决焦点管理混乱问题。
  • 局部化控件列表:每个子窗口拥有独立的win2_lstHandle,关闭后列表随函数上下文回收,不会残留已销毁控件的引用。
  • 修复字体拼写错误:将noraml改为normal,避免字体加载异常。
  • 添加窗口关闭回调:明确清空控件列表,进一步避免潜在的内存泄漏。

内容的提问来源于stack exchange,提问作者shbidibom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 06:00:01