Python canvas move ve rotate yi bir arada yapmak

Merhabalar. İki parklı py dosyası var. biri png imaj dosyasının dönmesi, diğeri de hareket etmesi. Acaba aynı anda imaj dosyası hem dönüp hem de hareket edebilir mi?

Hareket eden py dosyası

from tkinter import *
import time

root = Tk()

def next_image(event=None):
    canvas1.move(item, 10, 0)
        
image1 = "bir.png"
photo1 = PhotoImage(file=image1)

width1 = 800
height1 = 600

canvas1 = Canvas(width=width1, height=height1)
canvas1.pack(expand=1, fill=BOTH) # <--- Make your canvas expandable.
item = canvas1.create_image(50, 50, image=photo1) # <--- Save the return value of the create_* method.
canvas1.bind('<Button-1>', next_image)

root.mainloop() 

Dönen py dosyası

import tkinter as tk
from PIL import ImageTk
from PIL import Image

class SimpleApp(object):
    def __init__(self, master, filename, **kwargs):
        self.master = master
        self.filename = filename
        self.canvas = tk.Canvas(master, width=500, height=500)
        self.canvas.pack()

        self.update = self.draw().__next__
        master.after(100, self.update)

    def draw(self):
        image = Image.open(self.filename)
        angle = 0
        while True:
            tkimage = ImageTk.PhotoImage(image.rotate(angle))
            canvas_obj = self.canvas.create_image(
                250, 250, image=tkimage)
            self.master.after_idle(self.update)
            yield
            self.canvas.delete(canvas_obj)
            angle -= 2
            angle %= 360
            

root = tk.Tk()
app = SimpleApp(root, 'bir.png')
root.mainloop()

bir.png dosyası

bir

Evet aynı anda resim hem dönüp hem de doğrusal hareket yapabilir. Aşağıdaki kodu bir inceleyin isterseniz. Resmin üzerine tıklayıp, mausu basılı tuttuğunuz sürece dönme ve sağa doğru hareket etme işlemi gerçekleşecektir.

import tkinter as tk

from PIL import Image, ImageTk


class Object:
    def __init__(self, master, img):
        self.master = master
        self.img = img
        self.image = ImageTk.PhotoImage(self.img)
        self.master.images += [self.image]
        self.status = False
        self.master.create_image(
            (50, 50),
            image=self.image,
            tag="resim"
        )
        self.master.bind(
            "<ButtonPress-1>",
            lambda event: self.start()
        )
        self.master.bind(
            "<ButtonRelease-1>",
            lambda event: self.stop()
        )

    def start(self):
        self.status = True
        self.rotate_and_move()

    def stop(self):
        self.status = False

    def rotate_and_move(self):
        if self.status:
            self.img = self.img.rotate(45)
            self.image = ImageTk.PhotoImage(self.img)
            self.master.itemconfig(tagOrId="resim", image=self.image)
            self.master.move("resim", 5, 0)
            self.master.after(100, self.rotate)


def main():
    root = tk.Tk()
    canvas = tk.Canvas(master=root)
    canvas.pack()
    canvas.images = []
    img = Image.open("test.png")
    Object(master=canvas, img=img)
    root.mainloop()


if __name__ == "__main__":
    main()
3 Beğeni

Bu arada aşağıda kullandığım kodu bir üstte kullandığım koda tercih ederim.

Yaptığım değişiklikler şunlar:

  1. Döndürme işlemi bir önceki döndürülen nesne üzerinde gerçekleşiyordu. Yani bir resmi döndürünce, bir sonraki dönme hareketi bu yeni konuma göre yapılıyordu, bu da resmin bozulmasına neden oluyordu. Bunu iptal ettim, döndürme işlemi, resmin orijinal hali üzerinden gerçekleşecek, böylece resimde bozulmalar meydana gelmeyecek.
  2. Dönme açısını, birim zamanda x ve y eksenleri üzerinde yapılacak doğrusal hareket miktarını, koordinatları ve zamanı parametre olarak girebilirsiniz.
import tkinter as tk

from PIL import Image, ImageTk


class Object:
    def __init__(
            self,
            master,
            img,
            coordinates,
            rotation_angle,
            x_distance,
            y_distance,
            time
    ):
        self.master = master
        self.img = img
        self._img = img
        self.rotation_angle = rotation_angle
        self.x_distance = x_distance
        self.y_distance = y_distance
        self.time = time
        self.start_angle = 0
        self.image = ImageTk.PhotoImage(self.img)
        self.master.images += [self.image]
        self.status = False
        self.master.create_image(
            coordinates,
            image=self.image,
            tag="resim"
        )
        self.master.bind(
            "<ButtonPress-1>",
            lambda event: self.start()
        )
        self.master.bind(
            "<ButtonRelease-1>",
            lambda event: self.stop()
        )

    def start(self):
        self.status = True
        self.rotate()

    def stop(self):
        self.status = False

    def rotate(self):
        if self.status:
            self.img = self._img.rotate(self.start_angle)
            self.image = ImageTk.PhotoImage(self.img)
            self.master.itemconfig(tagOrId="resim", image=self.image)
            self.master.move("resim", self.x_distance, self.y_distance)
            self.start_angle += self.rotation_angle
            self.master.after(self.time, self.rotate)


def main():
    root = tk.Tk()
    canvas = tk.Canvas(master=root)
    canvas.pack()
    canvas.images = []
    img = Image.open("test.png")
    Object(
        master=canvas,
        img=img,
        rotation_angle=10,
        x_distance=1,
        y_distance=0,
        time=10,
        coordinates=(50, 50)
    )
    root.mainloop()


if __name__ == "__main__":
    main()
1 Beğeni

Mesela şöyle de hem bir yörünge hem de kendi ekseni etrafında dönmesini sağlayabilirsiniz.

import tkinter as tk

from PIL import Image, ImageTk
from math import cos, sin, radians


class Object:
    def __init__(
            self,
            master,
            img,
            coordinates,
            orbital_rotation_angle,
            axial_rotation_angle,
            radius,
            time
    ):
        self.master = master
        self.img = img
        self._img = img
        self.x, self.y = coordinates
        self.orbital_rotation_angle = orbital_rotation_angle
        self.axial_rotation_angle = axial_rotation_angle
        self.time = time
        self.radius = radius
        self.orbital_start = 0
        self.axial_start = 0
        self.image = ImageTk.PhotoImage(self.img)
        self.master.images += [self.image]
        self.status = False
        self.master.create_image(
            self.x + self.radius * cos(radians(0)),
            self.y,
            image=self.image,
            tag="resim",
            anchor="center"
        )
        self.master.bind(
            "<ButtonPress-1>",
            lambda event: self.start()
        )
        self.master.bind(
            "<ButtonRelease-1>",
            lambda event: self.stop()
        )

    def start(self):
        self.status = True
        self.rotate()

    def stop(self):
        self.status = False

    def rotate(self):
        if self.status:
            self.img = self._img.rotate(self.axial_start)
            self.image = ImageTk.PhotoImage(self.img)
            self.master.itemconfig(tagOrId="resim", image=self.image)
            self.master.coords(
                "resim",
                self.x + self.radius * cos(radians(self.orbital_start)),
                self.y + self.radius * sin(radians(self.orbital_start))
            )
            self.orbital_start += self.orbital_rotation_angle
            self.axial_start += self.axial_rotation_angle
            self.master.after(self.time, self.rotate)


def main():
    root = tk.Tk()
    w, h = 500, 500
    canvas = tk.Canvas(master=root, width=w, height=h)
    canvas.pack(expand=True, fill="both")
    canvas.images = []
    img = Image.open("test.png")
    Object(
        master=canvas,
        img=img,
        orbital_rotation_angle=1,
        axial_rotation_angle=100,
        radius=100,
        time=10,
        coordinates=(w // 2, h // 2)
    )
    root.mainloop()


if __name__ == "__main__":
    main()
1 Beğeni

Hocam merhaba. İnternette tkinkter rotation animasyonu oluşturmanın yollarını ararken sizin cevabınıza denk geldim. Verdiğiniz çözümü kendi projemde denedim. Öncelikle elinize sağlık. Fakat ben tıklama ile başlayıp tıklamayı bırakınca durmasını değil de, benim istediğim anda başlayıp, istediğim yerde durmasını istiyorum. Nasıl bir yapı kurmam gerekir? Amacım bir çark görselini Tkinter ile ekrana yansıtmak, butona tıkladığımda çarkın dönmeye başlaması ve istediğim konuma geldiğinde kendiliğinden durması.

Merhaba,

Yapmanız gereken, bind ile canvas nesnesine atanan hareketi başlatma ve durdurma işlevlerini devre dışı bırakmak. Bir tane düğme oluşturup hareketi başlatma işlevini o düğmeye atayabilirsiniz. Dönen çarkı durdurmak için de belirli bir açı değerini kullanabilirsiniz. Çarkın ilk konumu ile son konumu arasındaki açısal fark, sizin belirlediğiniz açıya geldiğinde dönme işlemi otomatik olarak sonlandırılabilir.

Mevcut yapıyı referans alabilir, üzerinde bir takım değişiklikler yaptıktan sonra da istediğiniz yapıyı elde edebilirsiniz.

1 Beğeni