【问题标题】:Tkinter - How to move image from canvas in slow motionTkinter - 如何以慢动作从画布上移动图像
【发布时间】:2017-04-20 21:32:03
【问题描述】:

伙计们。我正在尝试创建自己的纸牌游戏版本。我在点击事件时尝试将我的卡片移动到画布中心时遇到以下问题。这是我的代码示例

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

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

【问题讨论】:

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


    【解决方案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()
    

    【讨论】:

    • 您好,请问如何通过更改delta_xdelta_y 的值来加快速度?
    • @sodmzs:你的意思是像delta_x = .5delta_x = 1.2
    • 没有。实际上我希望速度快一点,所以我将速度的值更改为speed=1,但它仍然比所需的输出慢一点。那我该怎么办?
    • 您是否尝试过将speed 更改为其他值?这只是基本的数学。在每个时间段内将对象移动更远的距离,或者每秒移动相同的距离但更多次。
    【解决方案2】:

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

    例如,如果您希望将卡片在 x 和 y 方向移动 400 个单位,则可以使用以下方法:

    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 变量以创建您认为正确的内容。

    【讨论】:

    • root.after(total_time/period) 正在有效地使应用程序进入睡眠状态。这不会带来良好的用户体验。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2021-06-28
      • 2013-11-18
      • 1970-01-01
      • 1970-01-01
      • 2013-10-31
      • 1970-01-01
      • 2018-11-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多