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