在tkinter画布上跟踪自己的对象

时间:2017-02-22 20:00:38

标签: python object canvas tkinter

到目前为止,每当我需要在tkinter画布上使用多种形状时,它们就是那种形状。我用canvas.find_all()得到了他们的标签,并通过移动,调整大小等来操纵他们的几何 但我碰到了这个问题,我似乎无法解决这个问题 如果我定义了一个自己的类并将该对象绘制到画布上,我如何跟踪画布上的所有对象,以便调用它们的方法?

假设我定义了一个Bubble类,它会在屏幕上绘制一个起泡的东西。每一秒之后,我希望它能改变所有气泡。使用change_colour方法将颜色转换为其他颜色。

my_list = []
for n in range(10):
    bubble = Bubble()
    my_list.append(bubble)

while True:
    time.sleep(1)
    for item in my_list:
        item.change_colour()

我可以将它附加到一个大的列表中,然后像我在这里一样迭代它,但对于有更多对象的情况,这太慢了!
这样做的正确方法是什么?
像往常一样,谢谢你的帮助!

正如所指出的,time.sleep()没有任何意义,但这不是我想要解决的问题。

2 个答案:

答案 0 :(得分:1)

如果您想对每个项目执行自定义的个别更改(例如,将每个项目的颜色更改为全新的随机颜色),那么除了遍历每个项目并调用itemconfig之外,您无法做得更好他们个人。

但是,如果您想对每个项目进行相同的更改,则可以使用该标记作为说明符标记您的项目并一次调用itemconfig

示例:

import Tkinter
import random

root = Tkinter.Tk()
canvas = Tkinter.Canvas(root, width=400, height=400)
canvas.pack()

for i in range(1000):
    x = random.randint(0, 400)
    y = random.randint(0, 400)
    canvas.create_oval((x-5,y-5,x+5,y+5), fill="white", tags=("bubble"))

current_color = "white"
def change_colors():
    global current_color
    current_color = "white" if current_color == "black" else "black"
    canvas.itemconfig("bubble", fill = current_color)
    root.after(1000, change_colors)

root.after(1000, change_colors)
root.mainloop()

结果:

enter image description here

然而,正如我在之前的评论中指出的那样,我仍然认为这是一个不成熟的优化。即使你有一千个项目,迭代它们并单独配置它们并不比使用标签那么慢。例如:

import Tkinter
import random

root = Tkinter.Tk()
canvas = Tkinter.Canvas(root, width=400, height=400)
canvas.pack()

items = []
for i in range(1000):
    x = random.randint(0, 400)
    y = random.randint(0, 400)
    id = canvas.create_oval((x-5,y-5,x+5,y+5), fill="white")
    items.append(id)

current_color = "white"
def change_colors():
    global current_color
    current_color = "white" if current_color == "black" else "black"
    for id in items:
        canvas.itemconfig(id, fill = current_color)
    root.after(1000, change_colors)

root.after(1000, change_colors)
root.mainloop()

答案 1 :(得分:1)

Canvas.find_withtag()方法将返回第一个参数指定的所有匹配对象的ID列表。您可以将它与字典结合使用,将它们映射回类的相应实例。一旦你有了,你可以调用它的任何方法。

import Tkinter
import random

BUBBLE_TAG = 'Bubble'
current_color = 'white'

class Bubble(object):
    def __init__(self, canvas, x, y, size, color):
        self.canvas = canvas
        self.id = canvas.create_oval((x-5,y-5,x+5,y+5), fill=color, 
                                     tags=BUBBLE_TAG)

    def change_color(self, new_color):
        self.canvas.itemconfigure(self.id, fill=new_color)

root = Tkinter.Tk()
canvas = Tkinter.Canvas(root, width=400, height=400)
canvas.pack()

mapping = {}
for i in range(1000):
    x, y = random.randint(0, 400), random.randint(0, 400)
    color = 'black' if random.randint(0, 1) else 'white'
    obj = Bubble(canvas, x, y, 5, color)
    mapping[obj.id] = obj

def change_colors():
    for id in canvas.find_withtag(BUBBLE_TAG):
        current_color = canvas.itemcget(id, 'fill')
        new_color = 'black' if current_color == 'white' else 'white'
        mapping[id].change_color(new_color)  # calls method of object
    root.after(1000, change_colors)

root.after(1000, change_colors)
root.mainloop()

以下是其运行示例:

sample of it running