【问题标题】:Moving balls in Tkinter Canvas在 Tkinter Canvas 中移动球
【发布时间】:2014-08-21 15:57:00
【问题描述】:

这是一个非常基本的程序,我想用它制作两个移动的球,但实际上只有一个球会移动。

我也尝试了一些变化,但无法让第二个球移动;另一个相关问题 - 有些人使用move(object) 方法来实现这一点,而其他人则使用delete(object) 然后重绘它。我应该使用哪一个?为什么?

这是我的代码,它只动画/移动一个球:

from Tkinter import *

class Ball:
    def __init__(self, canvas, x1, y1, x2, y2):
    self.x1 = x1
    self.y1 = y1
    self.x2 = x2
    self.y2 = y2
    self.canvas = canvas
    self.ball = canvas.create_oval(self.x1, self.y1, self.x2, self.y2, fill="red")

    def move_ball(self):
        while True:
            self.canvas.move(self.ball, 2, 1)
            self.canvas.after(20)
            self.canvas.update()

# initialize root Window and canvas
root = Tk()
root.title("Balls")
root.resizable(False,False)
canvas = Canvas(root, width = 300, height = 300)
canvas.pack()

# create two ball objects and animate them
ball1 = Ball(canvas, 10, 10, 30, 30)
ball2 = Ball(canvas, 60, 60, 80, 80)

ball1.move_ball()
ball2.move_ball()

root.mainloop()

【问题讨论】:

  • 请修正意图!

标签: python animation tkinter


【解决方案1】:

您永远不应该在 GUI 程序中放置无限循环——已经有无限循环在运行。如果您希望您的球独立移动,只需取出循环并让move_ball 方法在事件循环上对其自身进行新的调用。这样,您的球将永远继续移动(这意味着您应该在那里进行某种检查以防止这种情况发生)

我已经通过删除无限循环、稍微减慢动画速度以及对它们移动的方向使用随机值来稍微修改您的程序。所有这些更改都在 move_ball 方法中。

from Tkinter import *
from random import randint

class Ball:
    def __init__(self, canvas, x1, y1, x2, y2):
        self.x1 = x1
        self.y1 = y1
        self.x2 = x2
        self.y2 = y2
        self.canvas = canvas
        self.ball = canvas.create_oval(self.x1, self.y1, self.x2, self.y2, fill="red")

    def move_ball(self):
        deltax = randint(0,5)
        deltay = randint(0,5)
        self.canvas.move(self.ball, deltax, deltay)
        self.canvas.after(50, self.move_ball)

# initialize root Window and canvas
root = Tk()
root.title("Balls")
root.resizable(False,False)
canvas = Canvas(root, width = 300, height = 300)
canvas.pack()

# create two ball objects and animate them
ball1 = Ball(canvas, 10, 10, 30, 30)
ball2 = Ball(canvas, 60, 60, 80, 80)

ball1.move_ball()
ball2.move_ball()

root.mainloop()

【讨论】:

  • 啊 - 非常感谢 Bryan,效果很好(更重要的是我理解)!我认为向它添加实际功能(例如弹跳和加速)并不难。
  • 如果我不想要任何图形怎么办? Tk 是否包含一种虚拟小部件,或任何其他带有 .after() 方法的东西来将循环与其他小部件放在一起
  • @yota:如果您不想要任何图形,请使用您自己的循环。 after 的使用是 tkinter 特有的解决方案——不过,这些概念可以应用于任何带有事件循环的工具包。
  • 对不起,它含糊了 :) Labjack U12 板提供了一个 python 框架,并显示了一个基于 Tkinter 的键盘和鼠标捕获解决方案,但是没有显示,所以我仍然可以使用 Tk 机器主循环并与其他应用程序相关逻辑(可能不是由事件触发)一起进行无缝键盘处理(使用 tk)。答案可能写在这里:stackoverflow.com/q/459083 :)
【解决方案2】:

这个函数似乎是罪魁祸首

def move_ball(self):
    while True:
        self.canvas.move(self.ball, 2, 1)
        self.canvas.after(20)
        self.canvas.update()

你在调用的时候故意让自己陷入无限循环。

ball1.move_ball()    # gets called, enters infinite loop
ball2.move_ball()    # never gets called, because code is stuck one line above

【讨论】:

    【解决方案3】:

    它只移动一个,因为程序一次只读取一个变量。如果您将程序设置为在球到达某个位置时读取,例如画布的末端,您可以编写程序以读取下一行并触发第二个球移动。但是,这一次只能移动一个。

    你的程序确实卡在了这条线上:

    ball1.move_ball()

    而且它永远不会排队:

    ball2.move_ball()

    因为循环的结束位置没有限制。

    否则,“sundar nataraj”的答案就可以了。

    【讨论】:

      【解决方案4】:

      试试 而不是self.canvas.move(self.ball, 2, 1) 使用

      self.canvas.move(ALL, 2, 1)
      

      所有这些都用于移动画布中的所有对象

      【讨论】:

      • 感谢您的快速回复。如果我在 move 方法中使用“ALL”,这确实会为两者设置动画,但我想让它们独立移动(对于任意数量的球),使用 .move(ALL, x, y) 将移动画布在相同的 x,y 方向。也许我不应该首先使用 while 循环来执行此操作?
      • @Kazark All 用于移动画布中的所有对象。但 OP 需要尝试不同的 .我认为他明白这一点
      • 我留下该评论的原因是因为您的帖子出现在低质量的审核队列中。通常,“尝试...”作为评论比作为答案更好。 “做...”是一个很好的答案。
      猜你喜欢
      • 2011-12-20
      • 2020-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-13
      • 1970-01-01
      • 1970-01-01
      • 2016-08-05
      相关资源
      最近更新 更多