Home > Enterprise >  Tkinter Toplevel window with autoresize background image does not work
Tkinter Toplevel window with autoresize background image does not work

Time:04-15

I am able to create a normal window in tkinter having a background image resizing with the window itself. But I am not able to do the same thing for a Toplevel window. The TopWin window derived from Toplevel resize indefinitely without doing any action. I do not understand why and what is the problem. I reported below my test code:

from tkinter import *
from PIL import Image, ImageTk

class FrameWin(Frame):
    def __init__(self, master, *pargs):
        Frame.__init__(self, master, *pargs)
        self.image = Image.open("../idata/bkg-3.png")
        self.img_copy= self.image.copy()
        self.background_image = ImageTk.PhotoImage(self.image)
        self.background = Label(self, image=self.background_image)
        self.background.pack(fill=BOTH, expand=YES)
        self.background.bind('<Configure>', self._resize_image)
    #---------------------------------------------------------------------------

    def _resize_image(self,event):
        new_width = event.width
        new_height = event.height
        self.image = self.img_copy.resize((new_width, new_height))
        self.background_image = ImageTk.PhotoImage(self.image)
        self.background.configure(image = self.background_image)
    #---------------------------------------------------------------------------
#---------------------------------------------------------------------------
#---------------------------------------------------------------------------

class TopWin(Toplevel):
    def __init__(self, master, **kwargs):
        # super().__init__(**kwargs)
        Toplevel.__init__(self, **kwargs)
        self.image = Image.open("../idata/bkg-3.png")
        self.img_copy= self.image.copy()
        self.background_image = ImageTk.PhotoImage(self.image)
        self.background = Label(self, image=self.background_image)
        self.background.pack(fill=BOTH, expand=YES)
        self.background.bind('<Configure>', self._resize_image)
    #---------------------------------------------------------------------------

    def _resize_image(self,event):
        new_width = event.width
        new_height = event.height
        self.image = self.img_copy.resize((new_width, new_height))
        self.background_image = ImageTk.PhotoImage(self.image)
        self.background.configure(image = self.background_image)
    #---------------------------------------------------------------------------
#---------------------------------------------------------------------------
#---------------------------------------------------------------------------


def workingMain():
    root = Tk()
    root.title("Title")
    root.geometry("600x400")
    root.configure(background="black")

    w = FrameWin(root)
    w.pack(fill=BOTH, expand=YES)
    root.mainloop()
#---------------------------------------------------------------------------

def notWorkingMain():
    root = Tk()
    root.title("Title")
    root.geometry("600x400")
    root.configure(background="black")
    w = TopWin(root)

    root.mainloop()
#---------------------------------------------------------------------------

notWorkingMain()
#---------------------------------------------------------------------------
#---------------------------------------------------------------------------

CodePudding user response:

FrameWin works because you use fill = BOTH and expand = YES on the label and frame. I'm not certain why this makes it work, but I think that when the window is resized, the label is also resized which triggers the Configure event and resizes the image to the dimensions of the window. If you don't use fill and expand, the image will resize repeatedly until it fills the window, similar to the problem you face with TopWin as the Configure event is called until the label fills the window. Once it fills the window, it can't expand any more so Configure stops being called.

To resolve this, you can add a check the resize method to check if the window and image sizes are the same. If they're not, you expand the image. This prevents the image from expanding indefinitely. Note that the event binding is on the TopLevel itself, not the Label.

class TopWin(Toplevel):
    def __init__(self, master, **kwargs):
        # super().__init__(**kwargs)
        Toplevel.__init__(self, **kwargs)
        self.image = Image.open("../idata/bkg-3.png")
        self.img_copy= self.image.copy()
        self.background_image = ImageTk.PhotoImage(self.image)
        self.background = Label(self, image=self.background_image)
        self.background.pack(fill=BOTH, expand=YES)
        self.bind('<Configure>', self._resize_image) # Bind the toplevel, not the label
    #---------------------------------------------------------------------------

    def _resize_image(self,event):
        # These are now the height/width of the window
        new_width = event.width
        new_height = event.height
        # Check if the image is the same size as the window
        if self.background.winfo_width() != new_width or self.background.winfo_height() != new_height:
            # If it isn't, resize
            self.image = self.img_copy.resize((new_width, new_height))
            self.background_image = ImageTk.PhotoImage(self.image)
            self.background.configure(image = self.background_image)
  • Related