-1

I wrote an application with tkinter that uses classes as structure. I stick very close to the often seen sentdex structure (See link: Tkinter and ttk in python 2.7), where every new page is basically a frame which is raised to the top via a controller function. Currently I am trying to find a solution for automatically resizing background images when the root window is maximized/minimized. I found a solution but it doesn't fit my needs to 100% because here the function is in the same class as the image: (See link: Tkinter resize background image to window size (Python 3.4))

I need a general function which takes a reference to page (to know where to resize an image) and then resizes an image which is - in best case - saved on this particular page.

All my attempts to use lambda: controller failed. I would be very glad if someone could hinder me from hardcoding the resizeimage-function on every page.

This is my code:

import tkinter as tk
from tkinter import font  as tkfont
from PIL import Image, ImageTk

Here I create the controller class :

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)


        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}
        for F in (StartPage, PageOne):
            page_name = F.__name__
            frame = F(container,self)
            self.frames[page_name] = frame
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("StartPage")

    def show_frame(self, page_name):
        #Show a frame for the given page name
        frame = self.frames[page_name]
        frame.tkraise()

This is the resizeImage-function I try to code:

    def resizeImage(self):

        # give me an image
        img = self.frames[StartPage].img
        # give me an image copy
        img_copy = self.frames[StartPage].img_copy
        # give me background image
        background_image = self.frames[StartPage].background_image

        new_width = event.width
        new_height = event.height

        img = img_copy.resize((new_width, new_height))

        background_image = ImageTk.PhotoImage(img)
        background.configure(image= background_image)

This frame contains an image which should be resized via controller-function

class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)


        self.img = Image.open("*.png")

        self.img_copy= self.img.copy()

        self.background_image = ImageTk.PhotoImage(self.img)

        self.background = tk.Label(self, image=self.background_image)
        self.background.grid()
        self.background.bind('<Configure>',controller.resizeImage())

And finally this is an empty frame/page just to make sure that the loop in the controller class works:

class PageOne(tk.Frame):
# this is an empty frame
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()
martineau
  • 119,623
  • 25
  • 170
  • 301
Johannes Wiesner
  • 1,006
  • 12
  • 33

1 Answers1

0

I followed the advice from Nae :)

Thanks pal!

import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk

# Custom Label Class

class ResizingLabel(tk.Label): #inherit from Label Class
    def __init__(self, parent, imagepath, *args, **kwargs): # specific for this Subclass: give me an image-path and resize image to label-size
        tk.Label.__init__(self, parent, *args, **kwargs)  # I can do everything what tk.Label can do

        # Default configure settings (Label has no border)
        self.configure(bd=0)

        self.parent=parent
        self.parent.bind('<Configure>', self._resize_image)

        self.imagepath = imagepath
        self.image = Image.open(self.imagepath)
        self.img_copy= self.image.copy()
        self.background_image = ImageTk.PhotoImage(self.image)
        self.background = tk.Label(self, image=self.background_image,bd=0)
        self.background.grid(row=0,column=0,sticky="NSEW")
        self.background.grid_rowconfigure(0,weight=1)
        self.background.grid_columnconfigure(0,weight=1)
        self.background.bind('<Configure>', self._resize_image)

    def _resize_image(self,event):

        new_width = self.parent.winfo_width()
        new_height = self.parent.winfo_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)


# For the follwing code: See SentDex-Tutorial

LARGE_FONT= ("Verdana", 12)
class SeaOfBTC(tk.Tk):

    def __init__(self, *args, **kwargs):

        tk.Tk.__init__(self, *args, **kwargs)

        tk.Tk.wm_title(self,"Sea of BTC")

        container = tk.Frame()
        container.pack(side="top", fill="both", expand = True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}

        for F in (StartPage, PageOne):
            frame = F(container,self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(StartPage)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()

class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)

        # Create string object with path
        path = "banner.png"
        # Create custom label with reference to path
        label = ResizingLabel(self, path)
        label.grid()

        # Create example button on top of custom label
        button = tk.Button(label,text="Example Button")
        button.grid(column=0,row=0)

class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        # This frame contains nothing (only exists so that for-loop (see above) can iterate)

app = SeaOfBTC()
app.mainloop()
Johannes Wiesner
  • 1,006
  • 12
  • 33