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)