【问题标题】:Tkinter create shrinking circle on each mouse click, how to make it work with multiple clicks?Tkinter 在每次鼠标点击时创建一个缩小的圆圈,如何让它在多次点击时工作?
【发布时间】:2018-05-31 21:10:03
【问题描述】:

我正在创建一个简单的程序,该程序通过每次鼠标单击在每个单击位置上绘制一个随机颜色的缩小圆圈。每次单击都会创建一个直径为 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()

【问题讨论】:

  • 如果你想要多个圈子,你将需要使用和数组,而不仅仅是一个circ 变量
  • 您可能希望在一个自包含的类中构建圆圈,该类在调用时将调用一个新的类实例并运行到完成。
  • @LioraHaydont 实际上根本不需要数组。所有这些都可以在具有嵌套函数或类的自包含函数中完成。

标签: python-3.x function tkinter bind tkinter-canvas


【解决方案1】:

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

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

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()

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

您可以使用嵌套函数并避免使用全局函数。您的问题实际上是由于一切都依赖于全局变量而引起的。

试试下面的代码以获得非类选项。

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()

【讨论】:

  • 非常感谢。我还在学习,对课程还不完全熟悉。但我认为这是正确的方法。
  • @Blacho 当我刚开始的时候,我也不确定如何处理课程,但是一旦你花时间学习和理解它们,它们就会非常有帮助。
  • @Blacho 我在我的回答中也为你添加了一个非类选项。
【解决方案2】:

如上所述,您不需要类来解决这个问题,也不需要嵌套函数。正如@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()

【讨论】:

  • 我不同意这可以在没有类或嵌套函数的情况下完成我不明白 Liora 是如何暗示局部变量的,当他明确表示“需要使用和数组”假设并且是一个错字。您能否向我解释一下这是对局部变量的暗示,因为我不确定我是否理解?
  • @Mike-SMT,对我来说,关键短语是“不只是一个 circ 变量”,这是正确的。带有单个全局 circ 变量的原始设计注定要失败。全局数组是一种可能的解决方案,但我认为您和我都同意这不是最好的方法。
  • 是的。数组可以像许多其他选项一样工作,但最简单的解决方案可能是您提供的解决方案。就我个人而言,我会使用一个类,因为当代码增长时,它会更容易维护。也就是说,对于您回答的这个特定问题,可能是最佳/最简单的解决方案。
猜你喜欢
  • 2016-02-28
  • 1970-01-01
  • 2014-03-09
  • 1970-01-01
  • 2021-09-28
  • 2023-03-14
  • 1970-01-01
  • 2017-09-10
  • 2017-10-06
相关资源
最近更新 更多