tkinter 创建的屏保
- bug : 程序提示小球移动时最大递归深度超过限制
import random
import tkinter
class RandomBoll:
def __init__(self, canvas, screen_width, screen_height):
self.screenwidth = screen_width
self.screenheight = screen_height
self.canvas = canvas
self.xPos = random.randint(10, int(self.screenwidth - 20))
self.yPos = random.randint(10, int(self.screenheight - 20))
self.xSpeed = random.randint(4, 20)
self.ySpeed = random.randint(4, 20)
self.radios = random.randint(20, 120)
self.color = '#%02x%02x%02x' % (random.randint(0, 255),
random.randint(0, 255),
random.randint(0, 255))
def create_ball(self):
x1 = self.xPos - self.radios
y1 = self.yPos - self.radios
x2 = self.xPos + self.radios
y2 = self.yPos + self.radios
self.item = self.canvas.create_oval(x1, y1,
x2, y2,
fill=self.color,
outline=self.color)
def move_ball(self):
self.xPos += self.xSpeed
self.yPos += self.ySpeed
if self.xPos + self.radios >= self.screenwidth or self.xPos < self.radios:
self.xSpeed = -self.xSpeed
if self.yPos + self.radios >= self.screenheight or self.yPos < self.radios:
self.ySpeed *= -1
self.canvas.move(self.item, self.xSpeed, self.ySpeed)
class ScreenSaver:
balls = list()
def __init__(self):
self.numBalls = random.randint(6, 20)
self.root = tkinter.Tk()
self.root.overrideredirect(1)
self.root.bind('<Motion>', self.my_quit)
w, h = self.root.winfo_screenwidth(), self.root.winfo_screenheight()
self.canvas = tkinter.Canvas(self.root, width=w, height=h)
self.canvas.pack()
for i in range(self.numBalls):
ball = RandomBoll(self.canvas, screen_width=w, screen_height=h)
ball.create_ball()
self.balls.append(ball)
self.run_screen_saver()
self.root.mainloop()
def run_screen_saver(self):
for ball in self.balls:
ball.move_ball()
self.canvas.after(200, self.run_screen_saver())
def my_quit(self, e):
self.root.destroy()
if __name__ == '__main__':
ScreenSaver()
代码调试报错:
C:\Users\Administrator\AppData\Local\Programs\Python\Python37\python3.7.exe E:/Python_work/ziqizhan/ScreenSaver.py
Traceback (most recent call last):
File "E:/Python_work/ziqizhan/ScreenSaver.py", line 74, in <module>
ss = ScreenSaver()
File "E:/Python_work/ziqizhan/ScreenSaver.py", line 61, in __init__
self.run_screen_saver()
File "E:/Python_work/ziqizhan/ScreenSaver.py", line 67, in run_screen_saver
self.canvas.after(200, self.run_screen_saver())
File "E:/Python_work/ziqizhan/ScreenSaver.py", line 67, in run_screen_saver
self.canvas.after(200, self.run_screen_saver())
File "E:/Python_work/ziqizhan/ScreenSaver.py", line 67, in run_screen_saver
self.canvas.after(200, self.run_screen_saver())
[Previous line repeated 991 more times]
File "E:/Python_work/ziqizhan/ScreenSaver.py", line 66, in run_screen_saver
ball.move_ball()
File "E:/Python_work/ziqizhan/ScreenSaver.py", line 41, in move_ball
self.canvas.move(self.item, self.xSpeed, self.ySpeed)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 2591, in move
self.tk.call((self._w, 'move') + args)
RecursionError: maximum recursion depth exceeded while calling a Python object
Process finished with exit code 1
- 问题原因:
第67行传递的参数为
self.canvas.after(200, self.run_screen_saver())
该局语句的含义为:200毫秒之后开始调用函数run_screen_saver方法,而并非将run
_screen_saver的函数地址传递给函数after
def after(self, ms, func=None, *args):
"""Call function once after given time.
MS specifies the time in milliseconds. FUNC gives the
function which shall be called. Additional parameters
are given as parameters to the function call. Return
identifier to cancel scheduling with after_cancel."""
if not func:
# I'd rather use time.sleep(ms*0.001)
self.tk.call('after', ms)
return None
after函数中缺失存在 if not func 就开始调用self.tk.call,与报错信息相符合,在学习中应该注意函数作为参数传入,和直接调用函数的区别。
纠正后参数为:
self.canvas.after(200, self.run_screen_saver)