Tkinter - 如何以慢动作从画布移动图像

时间:2017-04-20 21:32:04

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

人。我正在尝试创建自己的纸牌游戏版本。在点击事件中尝试将卡片移动到画布中心时出现以下问题。这是我的代码的一个例子

import tkinter as tk

class gui(tk.Frame):

def __init__(self, parent, *args, **kwargs):
    tk.Frame.__init__(self, parent, *args, **kwargs)
    self.canvas =  tk.Canvas(parent, bg="blue", highlightthickness=0)
    self.canvas.pack(fill="both", expand=True)
    self.img = PhotoImage(file="card.gif")
    self.card = self.canvas.create_image(10, 10, image=self.img)
    self.canvas.tag_bind(self.card, '<Button-1>', self.onObjectClick1)

def onObjectClick1(self, event):
    if self.canvas.find_withtag("current"):
        x = 400
        y = 400
        self.canvas.coords("current", x, y)
        self.canvas.tag_raise("current")

if __name__ == "__main__":
root = tk.Tk()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.geometry("%dx%d+0+0" % (w, h))
gui(root)
root.mainloop()

我想要的是移动我的卡但不仅仅是从一个坐标移动到另一个坐标,而是以慢动作效果给它。

3 个答案:

答案 0 :(得分:1)

为了让你的卡片“动画”移动,可以使用一个系统来分解要移动的总距离,然后在一段时间内移动/更新较小的距离。

例如,如果您希望将卡片移动到x&amp ;; y,这样的事情可以起作用:

total_time = 500 #Time in milliseconds
period = 8
dx = 400/period
dy = 400/period

for i in range(period):
    self.canvas.move(chosen_card, dx, dy)
    root.after(total_time/period) #Pause for time, creating animation effect
    root.update() #Update position of card on canvas

这可能是动画的基本前提。当然,您需要在我的示例中编辑total_timeperiod变量,以创建您认为正确的内容。

答案 1 :(得分:1)

基本思想是编写一个移动对象少量的函数,然后调度自身以在短暂延迟后再次调用。它一直到达目的地。

这是一个非常简单的示例,可以独立移动几个项目。您可以通过更改speed参数或更改delta_xdelta_y的值来调整速度。

这是一个非常简单的算法,只是将x和y坐标增加一个固定的量。您可以改为沿曲线或直线计算等间距点。无论如何,动画技术仍然保持不变。

import Tkinter as tk

def move_object(canvas, object_id, destination, speed=50):
    dest_x, dest_y = destination
    coords = canvas.coords(object_id)
    current_x = coords[0]
    current_y = coords[1]

    new_x, new_y = current_x, current_y
    delta_x = delta_y = 0
    if current_x < dest_x:
        delta_x = 1
    elif current_x > dest_x:
        delta_x = -1

    if current_y < dest_y:
        delta_y = 1
    elif current_y > dest_y:
        delta_y = -1

    if (delta_x, delta_y) != (0, 0):
        canvas.move(object_id, delta_x, delta_y)

    if (new_x, new_y) != (dest_x, dest_y):
        canvas.after(speed, move_object, canvas, object_id, destination, speed)

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

item1 = canvas.create_rectangle(10, 10, 30, 30, fill="red")
item2 = canvas.create_rectangle(360, 10, 380, 30, fill="green")

move_object(canvas, item1, (200, 180), 25)
move_object(canvas, item2, (200, 220), 50)

root.mainloop()

答案 2 :(得分:0)

下面这段代码(准备复制/粘贴并按原样运行)在我的盒子上提供了一个很好的平滑动作:

import tkinter as tk
import time

class gui(tk.Frame):

    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.canvas =  tk.Canvas(parent, bg="blue", highlightthickness=0)
        self.canvas.pack(fill="both", expand=True)
        self.img = tk.PhotoImage(file="card.gif")
        self.card = self.canvas.create_image(10, 10, image=self.img)
        self.canvas.tag_bind(self.card, '<Button-1>', self.onObjectClick1)

    def onObjectClick1(self, event):
        if self.canvas.find_withtag("current"):
            x = 400
            y = 400
            self.canvas.coords("current", x, y)
            self.canvas.tag_raise("current")
            total_time = 500 #Time in milliseconds
        period = 400
        dx = 400/period
        dy = 400/period
        for i in range(period):
            self.canvas.move(self.card, dx, dy) # chosen_card
            time.sleep(0.01)
            # root.after(total_time/period) #Pause for time, creating animation effect
            root.update() #Update position of card on canvas

if __name__ == "__main__":
    root = tk.Tk()
    w, h = root.winfo_screenwidth(), root.winfo_screenheight()
    root.geometry("%dx%d+0+0" % (w, h))
    gui(root)
    root.mainloop()