Tkinter多图像窗口生成异常:仅显示2个而非4个的问题求助
问题排查与代码修正:Tkinter多窗口生成异常
问题根源分析
我帮你梳理下代码里的几个关键问题,这就是为啥你只看到两个窗口,而且第一个窗口用了列表最后一组坐标的原因:
- Lambda闭包延迟绑定:你在
for循环里用lambda:ShowAnotherWin(i)传递参数,但是lambda不会立刻捕获当前的i值,而是等到after触发执行时才去读取i的当前值。这时候循环已经跑完了,i已经是列表里的最后一个元素'150',所以四个after调用其实都传了同一个值,导致四个窗口完全重叠在一起,看起来就像一个窗口。 - 图片对象被垃圾回收:在
ShowAnotherWin函数里,image是局部变量,函数执行结束后Python会回收这个对象,导致Tkinter无法显示图片,窗口会变成空白。 - 多余的
mainloop()调用:每个Toplevel窗口不需要单独调用win.mainloop(),因为主窗口root的mainloop()已经在处理所有事件了,重复调用会导致程序阻塞,影响窗口生成。
修正后的代码
下面是修复了所有问题的代码,你可以直接运行:
from tkinter import * from PIL import ImageTk, Image def ShowAnotherWin(pos): win = Toplevel() # 加载图片并保存为窗口属性,避免被垃圾回收 image = ImageTk.PhotoImage(Image.open('C:/Users/capture.PNG')) win.image = image # 设置窗口位置,这里x和y都用pos,如果你需要不同的x/y可以调整列表内容 win.geometry(f'420x544+{pos}+{pos}') canvas = Canvas(win, width=420, height=560) canvas.create_image(0, 0, image=image, anchor=NW) canvas.pack() win.overrideredirect(1) YourImageList = ['0', '50', '100', '150'] root = Tk() # 修复lambda参数绑定问题,用默认参数捕获当前循环的i值 for i in YourImageList: root.after(0, lambda pos=i: ShowAnotherWin(pos)) # 主窗口的图片同样保存为root的属性 root_image = ImageTk.PhotoImage(Image.open('C:/Users/capture.PNG')) root.image = root_image root.geometry('420x560+1000+0') canvas = Canvas(root, width=420, height=560) canvas.create_image(0, 0, image=root_image, anchor=NW) canvas.pack() root.overrideredirect(1) root.mainloop()
关键修复点说明
- Lambda参数绑定:把
lambda:ShowAnotherWin(i)改成lambda pos=i: ShowAnotherWin(pos),通过默认参数的方式,把当前循环的i值直接绑定到lambda的参数里,这样每个lambda都会保存自己对应的i值,不会等到循环结束再取。 - 图片对象持久化:把每个窗口的
image对象赋值给窗口的属性(比如win.image、root.image),这样Python的垃圾回收机制就不会把图片对象删掉,Tkinter就能正常显示图片了。 - 移除多余的
mainloop():删掉ShowAnotherWin里的win.mainloop(),只保留主窗口的root.mainloop(),确保事件循环正常运行。
这样修改后,程序会生成主窗口加上四个分别位于(0,0)、(50,50)、(100,100)、(150,150)的图像窗口,每个窗口都能正确显示图片,坐标也和列表里的对应上啦。
内容的提问来源于stack exchange,提问作者user13027134
相关产品推荐
相关产品推荐

