Home
Navigation
Impressum
Coder Welten - Programmierung und Optimierung
Coder Welten
 
 

 

 

Tkinter: Simple 2D-Animationen mit Python und PIL

Hinweis:

Das Script auf dieser Seite lief zwar bereits zufriedenstellend und für erste Test­zwecke war es und ist es immer noch geeignet, doch im Funktionsumfang sehr begrenzt. Zwischenzeitlich wurde es nicht, wie eigentlich geplant, überarbeitet, sondern völlig neu geschrieben. Der grundlegende Aufbau und Ablauf blieb erhal­ten, so dass es auch heute noch für erste Schritte als Einstieg genutzt werden kann.

Wer im Anschluss daran etwas tiefer einsteigen möchte, in die Entwicklung einer App für 2D Animationen mit Python und PIL, dem sei das kleine Projekt mit einem erweiterten Script empfohlen:

» Tkinter App: 2D Animationen für Sequenzen und Movie Szenen «

Beispiel:

Ansicht Simple Animation
Ansicht des Tkinter Widget-Fensters beim Start einer simplen Animation.

Mit "deepcopy" wird eine Copy des Background-Images erzeugt, in der ein oder mehrere Objekte mit "paste" eingefügt werden. Das ursprüngliche Background-Image wird dabei nicht verändert.
Bei jedem Fortschreiten mit der "after" Methode verändert sich nicht nur der Zähler­stand, sondern auch die xy-Position der Image-Objekte.

Code des ersten Animation-Scripts:

from tkinter import Tk, Frame, Label, Button, Checkbutton, Radiobutton, IntVar
from PIL import Image, ImageTk
from copy import deepcopy

class SimpleAnimation:
    """Eine Klasse für simple 2D Animationen mit Image-Objekten"""

    def __init__(self, im_bg = None, im_01 = None, im_02 = None):
        self.fenster = Tk()
        self.fenster.title("Simple Animationen")
        self.fenster.wm_iconbitmap("logo.ico")
        self.fenster.config(bg = "#808080")
 
        self.auswahl = IntVar()      # Auswahl Ein/Aus für Speicherung
        self.laufmal = IntVar()      # Für Auswahl mit Radiobuttons
        vier_buttons = {"50":50, "100":100, "150":150, "200":200}
        
        # Aufteilung in oberen und unteren Frame mit Buttons usw.
        self.frame_o = Frame(self.fenster, bg = "#808080", padx = 10)
        self.frame_u = Frame(self.fenster, bg = "#6f6352", padx = 10)
        self.fenbild = Label(self.frame_o, bd = 0)
        self.control = Label(
                       self.frame_u, bd = 4, bg = "#000", fg = "#40ff40",
                       width = 20, relief = "sunken", pady = 4)    
        self.checker = Checkbutton(
                       self.frame_u, text = "Mit Speicherung?",
                       bg = "#6f6352", fg = "#ecb200",
                       selectcolor = "#606060",
                       variable = self.auswahl,
                       command  = self.setzeAuswahl)
        self.starter = Button(
                       self.frame_u, text = "Start",
                       font = ("cambria", 10, "bold"), padx = 12,
                       command = self.bewegeObjekte)

        # Labels und Buttons im Fenster anordnen (packen)
        self.frame_o.pack(side = "top")
        self.fenbild.pack(padx = 20, pady = 20)
        self.frame_u.pack(side = "bottom", fill = "x")
        self.control.pack(side = "left", padx = 20, pady = 4)
        self.checker.pack(side = "left", padx =  2, pady = 4)

        for key, wert in vier_buttons.items():
            radiobb = Radiobutton(
                self.frame_u, text = key, bg = "#6f6352",
                fg = "#e2aa00",selectcolor = "#606060",
                variable = self.laufmal, value = wert,
                command  = self.setzeAuswahl)
            radiobb.pack(side = "left") 
        self.starter.pack(side = "left", padx = 2, pady = 4)

        # Images vor und nach dem Öffnen
        self.iopen_bg = im_bg  # Die zu öffnende Hintergrundgrafik
        self.iopen_01 = im_01  # Die zu öffnenden Image-Objekt-Dateien,
        self.iopen_02 = im_02  # falls vorhanden.
        self.image_bg = None   # Die geöffnete Hintergrundgrafik
        self.image_01 = None   # Die geöffneten Image-Objekt-Dateien,
        self.image_02 = None   # falls vorhanden.
        self.label_bg = None   # Die fürs Label zusammengefügten Images
        self.img_temp = None   # Die temporären Image-Dateien

        # Positionen bei Start und bei Veränderungen
        self.posx_01 = 0
        self.posy_01 = 0
        self.posx_02 = 0
        self.posy_02 = 0
        self.startwt = 0       # Der Startwert bei Aufruf und Durchlauf
        self.endwert = 0       # Der Endwert bis Ende der Animation
        self.speichg = 0       # Für Speicherung, Defaultwert ist False
        self.bildnum = 0       # Die laufende Bildnummer

    def main(self, px01 = None, py01 = None, px02 = None, py02 = None):
        if self.iopen_bg is not None:
            self.image_bg = Image.open(self.iopen_bg)
        if self.iopen_01 is not None:
            self.image_01 = Image.open(self.iopen_01).convert("RGBA")
        if self.iopen_02 is not None:
            self.image_02 = Image.open(self.iopen_02).convert("RGBA")

        if px01 is not None:
            self.posx_01 = px01
        if py01 is not None:
            self.posy_01 = py01
        if px02 is not None:
            self.posx_02 = px02
        if py02 is not None:
            self.posy_02 = py02

        # Aufruf zum Positionieren beim Öffnen des Fensters.
        if self.iopen_bg is not None:
            self.positioniereObjekte()
        else:
            self.fenbild.config(text = "Fehler beim Laden von Images!",
                                  bg = "#808080", fg = "#ffc949")

    def positioniereObjekte(self):
        self.img_temp = deepcopy(self.image_bg)

        # Die bewegten Objekte in jeder Runde neu ausrichten.
        if self.iopen_01 is not None:
            self.img_temp.paste(
            self.image_01, (self.posx_01,self.posy_01), self.image_01)

            # Falls _01 nicht vorhanden, so kann _02 nicht folgen.
            if self.iopen_02 is not None:
                self.img_temp.paste(
                self.image_02, (self.posx_02,self.posy_02), self.image_02)

            # Speichern aller Einzelbilder einer Animation
            if self.speichg == True:
                print(self.speichg)
                self.bildnum += 1
                ablage = "temps/temp-{0:03d}.png".format(self.bildnum)
                self.img_temp.save(ablage, "PNG")

        # Nur ausführen, wenn wenigsten _bg vorhanden ist.
        if self.iopen_bg is not None:
            self.label_bg = ImageTk.PhotoImage(self.img_temp)
            self.fenbild.config(image = self.label_bg)

    def bewegeObjekte(self):
        if self.startwt < self.endwert:
            self.fenster.after(400, self.bewegeObjekte)
            self.startwt += 1

            # Berechnung der Bahnen
            self.posy_01 += 1
            self.posy_02 += 1
            if self.startwt < 110:
                self.posx_01 += 1
                self.posx_02 -= 1

            # Aufruf zum Positionieren bei laufender Animation.
            self.positioniereObjekte()

            # Als Anzeige der laufenden Werte
            ausg  = "{0:d} - {1:d} | ".format(self.posx_01,self.posy_01)
            ausg += "{0:d} - {1:d} | ".format(self.posx_02,self.posy_02)
            ausg += "E {0:d}".format(self.endwert)
            self.control["text"] = ausg

    def setzeAuswahl(self):
        self.endwert = self.laufmal.get()
        self.speichg = self.auswahl.get()
        
# --- Instanziieren eines Objektes der Klasse SimpleAnimation ---------       

objekt00 = "images/background.jpg"
objekt01 = "images/kugel-01.png"
objekt02 = "images/kugel-02.png"

if __name__ == "__main__":
    instanz = SimpleAnimation(objekt00, objekt01, objekt02)
    instanz.main(10,10,308,10)
    instanz.fenster.mainloop()

Weiterlesen: 2D-Animationen » new «

 
Navigation

Einstieg in Python

 


OOP mit Python

 


Codes & Tutorials

 

Weitere Themen

Kleines Projekt

 


Copyright © Verlag Horst Müller - Stendal - 2006 - Impressum - Datenschutz - Nutzungsbedingungen