Tkinter鼠标移出绘图边界触发IndexError的修复方法咨询
修复Tkinter绘图代码的IndexError错误
问题场景
运行一段Tkinter绘图代码时,鼠标移出预先绘制的边界区域时,程序触发IndexError: list assignment index out of range错误。
报错信息
Exception in Tkinter callback Traceback (most recent call last): File "c:\Users\My PC\AppData\Local\Programs\Python\Python312\Lib\tkinter\__init__.py", line 1962, in __call__ return self.func(*args) ^^^^^^^^^^^^^^^^ File "c:\Windows\System32\awdkhjgeuyfsbiufhefse.py", line 4, in <lambda> K=__import__('tkinter');m=K.Tk();R,C,z,p=50,50,10,0;l=[[0]*C for _ in range(R)];c=K.Canvas(m,w=C*z,he=R*z,bg='#0c0c0c');c.pack();[c.create_line(0,i*z,C*z,i*z,fill='#1a1a1a')for i in range(R)];[c.create_line(j*z,0,j*z,R*z,fill='#1a1a1a')for j in range(C)];c.bind("<B1-Motion>",lambda e:d(e.x//z,e.y//z));m.bind("<space>",t);m.mainloop() ^^^^^^^^^^^^^^^^ File "c:\Windows\System32\awdkhjgeuyfsbiufhefse.py", line 1, in d def d(x,y):global l;l[y][x]=1;c.create_rectangle(x*z,y*z,(x+1)*z,(y+1)*z,fill='#fff',outline='') ~~~~^^^ IndexError: list assignment index out of range
完整代码
def d(x,y):global l;l[y][x]=1;c.create_rectangle(x*z,y*z,(x+1)*z,(y+1)*z,fill='#fff',outline='') def t(_=None):global p;p^=1;['',u()][p] def u():global l,K;l=[[1 if(l[y][x]==1 and sum(l[y+dy][x+dx]for dx,dy in((dx,dy)for dx in(-1,0,1)for dy in(-1,0,1)if(dx,dy)!=(0,0))if 0<=x+dx<C and 0<=y+dy<R)in(2,3))or(l[y][x]==0 and sum(l[y+dy][x+dx]for dx,dy in((dx,dy)for dx in(-1,0,1)for dy in(-1,0,1)if(dx,dy)!=(0,0))if 0<=x+dx<C and 0<=y+dy<R)==3)else 0 for x in range(C)]for y in range(R)];K=__import__('tkinter');c.delete("all");[c.create_line(0,i*z,C*z,i*z,fill='#1a1a1a')for i in range(R+1)];[c.create_line(j*z,0,j*z,R*z,fill='#1a1a1a')for j in range(C+1)];[[c.create_rectangle(x*z,y*z,(x+1)*z,(y+1)*z,fill='white',outline='')for x in range(C)if l[y][x]]for y in range(R)];m.after(100,u) if p else None K=__import__('tkinter');m=K.Tk();R,C,z,p=50,50,10,0;l=[[0]*C for _ in range(R)];c=K.Canvas(m,w=C*z,he=R*z,bg='#0c0c0c');c.pack();[c.create_line(0,i*z,C*z,i*z,fill='#1a1a1a')for i in range(R)];[c.create_line(j*z,0,j*z,R*z,fill='#1a1a1a')for j in range(C)];c.bind("<B1-Motion>",lambda e:d(e.x//z,e.y//z));m.bind("<space>",t);m.mainloop()
错误原因
当鼠标移出Canvas区域时,e.x或e.y会变为负数,或者超出Canvas的宽高范围,导致e.x//z或e.y//z计算出的x、y值超出了二维列表l的索引边界(l是50行50列,合法索引为x∈[0,49],y∈[0,49]),触发索引越界错误。
修复方案
方案1:修改d函数,增加边界检查
在访问列表l之前,先判断x、y是否在合法范围内,仅在合法时执行赋值和绘图操作:
def d(x,y): global l # 检查坐标是否在合法索引范围内 if 0 <= x < C and 0 <= y < R: l[y][x] = 1 c.create_rectangle(x*z, y*z, (x+1)*z, (y+1)*z, fill='#fff', outline='')
方案2:修改事件绑定的lambda表达式,提前过滤非法坐标
在调用d函数前先判断坐标是否合法,非法时不执行函数:
c.bind("<B1-Motion>", lambda e: d(e.x//z, e.y//z) if 0 <= e.x//z < C and 0 <= e.y//z < R else None)
两种方案任选其一即可,都能避免鼠标移出边界时触发索引越界错误。
内容的提问来源于stack exchange,提问作者Puzzled
相关产品推荐
相关产品推荐

