Tkinter 在每次鼠标点击时创建缩小的圆圈,如何让它与多次点击一起工作?

Tkinter create shrinking circle on each mouse click, how to make it work with multiple clicks?

我正在创建一个简单的程序,它通过每次鼠标单击在每个单击的位置绘制一个随机颜色的缩小圆圈。每次点击都会创建一个直径为 50 的圆,它会立即开始缩小到 0。每次点击都应该创建新的缩小圈。

但是,在我单击并创建另一个圆后,我的程序停止缩小第一个圆。它仅完全缩小最后创建的圆圈。所有其他人都保持静止。 我认为问题出在功能本身。它调用未完成的相同函数。如何使其 运行 多次(每次分别点击)?还是我的局部变量和全局变量有问题?

到目前为止,这是我的代码:

import tkinter
import random
c = tkinter.Canvas(width = 400, height = 300)
c.pack()

def klik(event):
    global x, y, farba, circ, r
    r = 50      #circle diameter
    x, y = event.x, event.y     #clicked position
    color = '#{:06x}'.format(random.randrange(256 ** 3))        #random  color picker
    circ = c.create_oval(x - r, y - r, x + r, y + r, fill=color)         #print circle
    print(x, y, farba)      #check clicked coordinates, not important
    if r < 50:      #reset size after each circle
        r = 50
    shrink()

def shrink():
    global circ, x, y, r
    print(r)        #check if countdown runs correctly
    if r > 0:
        r -= 1      #diameter shrinking
        c.coords(circ, x-r, y-r, x+r, y+r)      #changing circle size
        c.after(100, shrink)        #timer, size 1pt smaller until size is 0

c.bind('<Button-1>', klik)
tkinter.mainloop()

如果你把所有东西都移到一个 class 中,那么每个圆圈都是它自己的实例,不会相互干扰。

查看您的代码的以下修改版本。它可能并不完美,但应该是您使用它的良好基础。

import tkinter
import random


c = tkinter.Canvas(width = 400, height = 300)
c.pack()

class create_circles():
    def __init__(self, event):
        self.r = 50
        self.x, self.y = event.x, event.y
        self.color = '#{:06x}'.format(random.randrange(256 ** 3))
        self.circ = c.create_oval(self.x - self.r, self.y - self.r, self.x + self.r, self.y + self.r, fill=self.color)
        self.shrink()

    def shrink(self):
        if self.r > 0:
            self.r -= 1
            c.coords(self.circ, self.x-self.r, self.y-self.r, self.x+self.r, self.y+self.r)
            c.after(100, self.shrink)

c.bind('<Button-1>', create_circles)
tkinter.mainloop()

在 class 之外还有另一种方法可以做到这一点。

您可以使用嵌套函数并避免使用全局函数。你问题中的问题实际上是因为一切都依赖于全局变量。

试试下面的非class选项代码。

import tkinter
import random


c = tkinter.Canvas(width = 400, height = 300)
c.pack()

def klik(event):
    r = 50
    x, y = event.x, event.y
    color = '#{:06x}'.format(random.randrange(256 ** 3))
    circ = c.create_oval(x - r, y - r, x + r, y + r, fill=color)

    def shrink(r, x, y, color, circ):
        if r > 0:
            r -= 1
            c.coords(circ, x-r, y-r, x+r, y+r)
            c.after(100, shrink, r, x, y, color, circ)

    shrink(r, x, y, color, circ)

c.bind('<Button-1>', klik)
tkinter.mainloop()

如前所述,您不需要 类 来解决此问题或嵌套函数。正如@LioraHaydont 所暗示的那样,关键是您需要使用本地变量而不是全局变量:

import tkinter as tk
from random import randrange

def klik(event):
    r = 50  # circle radius
    x, y = event.x, event.y  # clicked position
    color = '#{:06x}'.format(randrange(256 ** 3))  # random color picker
    c = canvas.create_oval(x - r, y - r, x + r, y + r, fill=color)  # print circle
    canvas.after(100, shrink, c, x, y, r)

def shrink(c, x, y, r):
    if r > 0:
        r -= 1  # radius shrinking
        canvas.coords(c, x - r, y - r, x + r, y + r)  # changing circle size
        canvas.after(100, shrink, c, x, y, r)  # timer, size 1pt smaller until size is 0

canvas = tk.Canvas(width=400, height=300)
canvas.pack()
canvas.bind('<Button-1>', klik)

tk.mainloop()