首页 > 解决方案 > 可以使用 tkinter 按钮重复更改画布对象吗?

问题描述

我正在尝试创建一个 GUI 来表示三角形对称组的图形解释(即保持不变的等边三角形的反射和旋转)。理想情况下,我希望以动画方式执行此操作,但这超出了我的范围,所以我只是更改点上的标签,并希望使用按钮进行反射或旋转,但我不能让按钮实际更改我需要它们的坐标值。

我正在尝试在下面的代码中交换 p1、p2 和 p3 的坐标`

def rf(p1, p2, p3):
    p4=p3
    p3=p2
    p2=p4
def ro(p1, p2, p3):
    p4=p1
    p1=p2
    p2=p3
    p3=p4
    print(p4)
def buttons(p1, p2, p3):
    l=tk.Button(top, text="Rotate", command=ro(p1, p2, p3))
    k=tk.Button(top, text="Reflect", command=rf(p1, p2, p3))
    triangle(p1, p2, p3)
    text(p1, p2)
    k.pack()
    l.pack()
buttons(p1, p2, p3)
top.mainloop()

`

当我运行它并按下旋转按钮时, p1 以原始值打印,并且无论按下多少次按钮都只打印一次。我该如何解决这个问题,是否有更好的包可以实际制作动画?谢谢!

标签: pythontkintertkinter-canvas

解决方案


您不能将参数传递给这样的按钮中的命令。您所做的实际上是在创建按钮时评估 ro(p1, p2, p3) ,获取该方法的返回值(即 None )并将其保存为命令。因此,当您按下按钮时,它正在调用 None....当然,它什么也不做。

通常,当您制作按钮时,命令应该只是一个方法名称示例:l = tk.Button(top, text="Rotate", command=ro)

这是一个 python 的东西,你可以把整个方法当作变量来对待。所以也许可以这样做,并将方法更改为如下所示:

def ro():
    p4=p1
    p1=p2
    p2=p3
    p3=p4
    print(p4)

如果您确实需要传递参数,这是最常见的解决方法:

l = tk.Button(top, text="Rotate", command=lambda: ro(p1, p2, p3)

关于它为什么起作用有一个很长的解释,您可以查找 lambda 关键字在 python 中的作用以进一步理解它。

编辑,如评论中所述

以你现在的方式使用你的变量可能会导致一些奇怪的事情发生。即它不会“保存”对变量的更改。发生这种情况是因为您正在使用的变量的范围仅限于它们所使用的函数。也就是说,您正在使用的名称是在函数中创建的,因此一旦函数完成,它们就会被删除。有几种方法可以解决这个问题。

一种方法是全局保存名称,删除参数并告诉函数它们是全局的:

p1 = 5  # these are just examples, make sure they are established
p2 = 7  # on the root level, or at least on the level that your
p3 = 12 # button is made or lower

def ro():
    global p1, p2, p3 # this will insist on using the globally named variables and not things specific to this function
    p1, p2, p3 = p2, p3, p1 # oh, btw, you can do this to save space and not have to make a p4

在这种情况下,您将不得不删除 lambda 并让它调用 'ro' 作为命令。这将做你想要的,但有几个问题:

  1. 除了旋转这三件事之外,您不能将 ro() 方法用于其他任何事情
  2. 使用“全局”关键字通常不受欢迎,我个人从不使用它

您可能会满意的是,更像是这样的:

p = [14, 12, 83]
q = [1, 43, 18, 75]

def ro(x):
    first = x.pop(0)
    x.append(first)

print(p)
ro(p)
print(p)
print()
print(q)
ro(q)
print(q)

如果你运行它,你会看到它旋转了任意列表中的所有数字。这样,您可以将三角形存储在列表中,然后使您的按钮如下所示:

l=tk.Button(top, text="Rotate", command=lambda: ro(p))

它会更改给定给 ro() 命令的列表,您无需担心变量的范围,因为您将它与 'p' 一起传递ro(p),它会更改传递的任何内容。

我希望这会有所帮助。


推荐阅读