pythontkintercanvas

tk canvas telepromter text transparency problems


I have a fullscreen window with a fullscreen canvas. First I place a fullscreen background image in this canvas.

canvas = tk.Canvas(window, bg="white", bd=0)
canvas.pack(fill=tk.BOTH, expand=True)
canvas.update()

image = Image.open('bild.jpg')
newimage = image.resize((canvas.winfo_width(),canvas.winfo_height()),Image.LANCZOS)
photo = ImageTk.PhotoImage(newimage, master=canvas)
canvas.create_image(0, 0, anchor="nw", image=photo)
canvas.update()

Then I place a headline text on the top right and below this a longer text. The text is much longer than the screen height.

rectangle_width = int(canvas.winfo_width() * 0.45)
rectangle_x     = canvas.winfo_width() - rectangle_width

headblock = canvas.create_text(
    rectangle_x+10, 10,
    anchor='nw',
    text=headline,
    font=('Helvetica', 18, 'bold'),
    fill='black',
    width=rectangle_width - 20
)
x1, y1, x2, y2 = canvas.bbox(headblock)
textblock = canvas.create_text(
    rectangle_x+10, y2+10,
    anchor='nw',
    text=fulltext,
    font=('Helvetica', 14, 'normal'),
    fill='black',
    width=rectangle_width - 20
)
canvas.update()

Now I wan't to animate the long text, like a telepromter, moving slowly upwards, so that viewers can read the full text. This works fine with canvas.move()

def animate():
    canvas.move(textblock, 0, -1)
    x1, y1, x2, y2 = canvas.bbox(textblock)
    if y2 > canvas.winfo_height():
        window.after(60, animate)

But while the textblock is moving up it is shown behind the headline. The problem is the background image. That should always be visible. If I place headline and text in different objects, labels, canvas, whatever, they are not transparent anymore.

Has anyone a good idea, how move the only the long text, while the image is always visible and the headline stays static?


Solution

  • You can use another Canvas widget as the telepromter with a cropped image from the background image that makes it looks like transparent, then scroll the text inside it:

    import tkinter as tk
    from PIL import Image, ImageTk, ImageGrab
    
    headline = 'Headline'
    with open(__file__) as f:
        fulltext = f.read()
    
    window = tk.Tk()
    window.geometry('800x600')
    
    canvas = tk.Canvas(window, bg="white", bd=0)
    canvas.pack(fill=tk.BOTH, expand=True)
    canvas.update()
    
    image = Image.open('lena.jpg')
    newimage = image.resize((canvas.winfo_width(),canvas.winfo_height()),Image.LANCZOS)
    photo = ImageTk.PhotoImage(newimage, master=canvas)
    canvas.create_image(0, 0, anchor="nw", image=photo)
    #canvas.update()
    
    rectangle_width = int(canvas.winfo_width() * 0.45)
    rectangle_x     = canvas.winfo_width() - rectangle_width
    
    headblock = canvas.create_text(
        rectangle_x+10, 10,
        anchor='nw',
        text=headline,
        font=('Helvetica', 18, 'bold'),
        fill='black',
        width=rectangle_width-20
    )
    x1, y1, x2, y2 = canvas.bbox(headblock)
    
    rectangle_height = canvas.winfo_height() - y2 - 10
    
    telepromter = tk.Canvas(canvas, width=rectangle_width-20, height=rectangle_height-10, highlightthickness=0)
    canvas.create_window(rectangle_x+10, y2+10, window=telepromter, anchor='nw')
    # get the image at the required region
    img = newimage.crop((rectangle_x+10, y2+10, newimage.width, newimage.height))
    bg = ImageTk.PhotoImage(img)
    telepromter.create_image(0, 0, image=bg, anchor='nw')
    
    textblock = telepromter.create_text(
        0, 0,
        anchor='nw',
        text=fulltext,
        font=('Helvetica', 14, 'normal'),
        fill='black',
        width=rectangle_width
    )
    
    def animate():
        telepromter.move(textblock, 0, -1)
        x1, y1, x2, y2 = telepromter.bbox(textblock)
        if y2 > telepromter.winfo_height():
            window.after(50, animate)
    
    animate()
    window.mainloop()
    

    Result:

    enter image description here