Home > Blockchain >  How to animate a "movie style" credit reel with tkinter and canvas?
How to animate a "movie style" credit reel with tkinter and canvas?

Time:01-15

I am trying to create a "movie" style credit reel using tkinter's canvas. I'd like to iterate through a list of names and have them scroll across the window. While I've successfully gotten a single name to scroll, I'm struggling to iterate over several names.

I appreciate your help and apologies for any gross oversights on my part.

from tkinter import *
import time

window = Tk()
window.geometry("1920x1080")
window.title("Window 1")

canvas1 = Canvas(window, width=1920, height=1080, bg="green", bd=0, highlightthickness=0, relief='ridge')
canvas1.pack()


class CreditList:
    def __init__(self, text):
        self.text = text
        self.location = 1080

    def credit_roll_function(self):
        text = canvas1.create_text(960,self.location, text=self.text, anchor=S, fill="black",
                                   font="Time 40")
        while True:
            canvas1.move(text, 0, -3)
            window.update()
            time.sleep(.03)


credit_list = ["First Name", "Second Name", "Third Name"]

for credit in credit_list:
    item = CreditList(credit)
    item.credit_roll_function()


window.mainloop()

CodePudding user response:

Here's a simple way to do it that uses the universal widget after() method instead of calling time.sleep() which interferes with tkinter's mainloop(). Each time the class' roll_credits() method is called, it moves the text upward a little and schedules another call to itself if the text isn't at the top of the window yet.

import tkinter as tk
from tkinter.constants import *

class CreditList:
    def __init__(self, text):
        self.location = HEIGHT
        self.text = canvas.create_text(960, self.location, text='\n'.join(text),
                                       anchor=S, fill='black', font='Time 40')

    def roll_credits(self):
        xl, yt, xr, yb = canvas.bbox(self.text)
        if yb <= 0:  # Completely off top of screen?
            canvas.pack_forget()
            tk.Button(text='Quit', font=('Arial', 20), relief=GROOVE, bg='orange',
                      command=window.quit).place(x=WIDTH/2, y=HEIGHT/2, anchor=NW)
            return  # Stop.
        canvas.move(self.text, 0, -3)
        self.location -= 3
        window.after(DELAY, self.roll_credits)  # Keep going.


DELAY = 10  # Millisecs.

window = tk.Tk()
window.attributes('-fullscreen', True)
window.update_idletasks()
WIDTH, HEIGHT = window.winfo_width(), window.winfo_height()  # Get screen size.
window.geometry(f'{WIDTH}x{HEIGHT} 0 0')
window.title('Window 1')

canvas = tk.Canvas(window, width=WIDTH, height=HEIGHT, bg='green', bd=0,
                    highlightthickness=0, relief='ridge')
canvas.pack()

credits = 'First Name', 'Second Name', 'Third Name'
cl = CreditList(credits)
window.after(DELAY, cl.roll_credits)  # Start rolling credits "loop".
window.mainloop()

CodePudding user response:

If you give all of your text items the same tag, you can move them all at the same time. Another solution is to create a single text item that is created by joining all of your strings with a newline.

For example, the following code illustrates how to create all of the items with a given tag, then moves them all one pixel at a time every 33 ms until they no longer are visible.

import tkinter as tk

class CreditList(tk.Canvas):
    def __init__(self, master, **kwargs):
        super().__init__(master, **kwargs)

    def roll_credits(self, credit_list):
        x = self.winfo_width() // 2
        y = self.winfo_height()
        temp = self.create_text(0,0,text="Hello")
        bbox = self.bbox(temp)
        self.delete(temp)
        lineheight = bbox[3]-bbox[1]
        linespacing = 4

        for credit in credit_list:
            self.create_text(x, y, text=credit, anchor="n", tags=("credit",))
            y  = lineheight   linespacing

        self._animate()

    def _animate(self):
        self.move("credit", 0, -1)
        x0, y0, x1, y1 = self.bbox("credit")
        if y1 > 0:
            self.after(33, self._animate)

root = tk.Tk()
credits = CreditList(root)
credits.pack(side="top", fill="both", expand=True)

credit_list = 'First Name', 'Second Name', 'Third Name'
root.after(1000, credits.roll_credits, credit_list)

root.mainloop()

  •  Tags:  
  • Related