首页 > 解决方案 > Python3 Tkinter 和 Pillow:如何在画布上旋转图像

问题描述

我想通过单击画布来移动画布周围的乌龟,乌龟应该指向它移动的方向。移动部分可以工作,但旋转功能会导致图像失真和损坏。

我做错了什么,我该如何解决这个问题?

我有一个类可以将乌龟的图像添加到画布上:

class TurtleImage:
    """
    A Turtle image that will be placed on the canvas that is given in the ctor.
    The turtle can be moved around the canvas with the move() method.
    """

    def __init__(self, canvas : Canvas):
        self.__turtle_file : str = self.__find_file("turtle_example/turtle.png")
        self.__canvas = canvas
        self.__pilImage : PngImagePlugin.PngImageFile = PILImage.open(self.__turtle_file)
        self.__pilTkImage : ImageTk.PhotoImage = ImageTk.PhotoImage(self.__pilImage)
        self.__turtle_id : int = canvas.create_image(100,100, image=self.__pilTkImage)
        self.__is_moving = False

这个类还有一个方法可以让海龟在画布上移动。它在 x 方向、y 方向或两者上将海龟移动 1 个像素,然后在由 speed 参数确定的时间延迟后安排自己再次被调用。它还应该旋转海龟,使其指向正确的方向:

def move(self, dest_x : int, dest_y :int, speed : float = 0.1):
    self.__is_moving = True
    delay_ms = math.floor(1/speed)
    current_x, current_y = self.__canvas.coords(self.__turtle_id)

    delta_x = 1 if current_x < dest_x else -1 if current_x > dest_x else 0
    delta_y = 1 if current_y < dest_y else -1 if current_y > dest_y else 0
    angle = math.atan2(delta_y,delta_x)

    self.__rotate(angle)

    if (delta_x, delta_y) != (0, 0):
        self.__canvas.move(self.__turtle_id, delta_x, delta_y)

    if (current_x, current_y) != (dest_x, dest_y):
        self.__canvas.after(delay_ms, self.move, dest_x, dest_y, speed)
    else:
        self.__is_moving = False

因为画布没有旋转其对象的能力,所以我必须将对象替换为自身的旋转版本:

def __rotate(self, angle : float):
    self.__pilImage = self.__pilImage.rotate(angle)
    self.__pilTkImage = ImageTk.PhotoImage(self.__pilImage)
    self.__replace_image(self.__pilTkImage)

def __replace_image(self, new_image : ImageTk.PhotoImage):
    self.__canvas.itemconfig(self.__turtle_id, image = new_image)

四处移动可以正常工作,但是旋转功能会导致图像失真和损坏,并且每次调用都会变得更糟。

你能告诉我为什么这不起作用,我需要做什么来解决它?

这是该海龟在旋转前后的屏幕截图:

在此处输入图像描述 在此处输入图像描述

标签: python-3.xtkinterpython-imaging-library

解决方案


我找到了解决方案,我必须重新打开文件:

def __rotate(self, angle : float):
    self.__pilImage = PILImage.open(self.__turtle_file)
    self.__pilImage = self.__pilImage.rotate(angle)
    self.__pilTkImage = ImageTk.PhotoImage(self.__pilImage)
    self.__replace_image(self.__pilTkImage)

我不知道为什么。


推荐阅读