Search code examples
pythontkintertkinter-canvas

Auto resize Canvas to fit tkinter window


so I want to make the canvas fit all the window but currently it's like this: ss

I want to do it without hard coding the width and height when initiating the canvas.

here's the code:

import PIL.Image
from PIL import Image, ImageTk
from tkinter import *    

class ExampleApp(Frame):
    def __init__(self,master):
        Frame.__init__(self,master=None)
        self.canvas = Canvas(self)
        
        self.sbarv=Scrollbar(self,orient=VERTICAL)
        self.sbarh=Scrollbar(self,orient=HORIZONTAL)
        self.sbarv.config(command=self.canvas.yview)
        self.sbarh.config(command=self.canvas.xview)

        self.canvas.config(yscrollcommand=self.sbarv.set)
        self.canvas.config(xscrollcommand=self.sbarh.set)

        self.canvas.grid(row=0,column=0,sticky="nsew")
        self.sbarv.grid(row=0,column=1,stick="ns")
        self.sbarh.grid(row=1,column=0,sticky="ew")

        self.im = PIL.Image.open("a.png")
        self.imw,self.imh=self.im.size
        self.canvas.config(scrollregion=(0,0,self.imw,self.imh))
        self.tk_im = ImageTk.PhotoImage(self.im)
        self.canvas.create_image(0,0,anchor="nw",image=self.tk_im)   
   

if __name__ == "__main__":
    root=Tk()
    app = ExampleApp(root)
    app.grid(sticky="nsew")
    root.geometry(f"{1000}x{600}")
    root.mainloop()

Solution

  • You can bind a callback to resize the canvas when its parent is resized

    I've made some changes here to make this a more prototypical tkinter app example, e.g.: using import tkinter as tk, having the main app class inherit from tk.Tk, fix setting geometry, etc.

    import PIL.Image
    from PIL import Image, ImageTk
    import tkinter as tk
    
    
    class ExampleApp(tk.Tk):
        def __init__(self) -> None:
            super().__init__()  # initialize Tk
            self.geometry('1000x600')
            self.canvas = tk.Canvas(self)
    
            self.sbarv = tk.Scrollbar(self, orient='vertical')
            self.sbarh = tk.Scrollbar(self, orient='horizontal')
            self.sbarv.config(command=self.canvas.yview)
            self.sbarh.config(command=self.canvas.xview)
    
            self.canvas.config(yscrollcommand=self.sbarv.set)
            self.canvas.config(xscrollcommand=self.sbarh.set)
            
            # bind the callback to dynamically resize the canvas
            self.bind('<Configure>', self.resize_canvas)
    
            self.canvas.grid(row=0, column=0, sticky='nsew')
            self.sbarv.grid(row=0, column=1, stick='ns')
            self.sbarh.grid(row=1, column=0, sticky='ew')
    
            self.im = PIL.Image.open('a.png')
            self.imw, self.imh = self.im.size
            self.canvas.config(scrollregion=(0, 0, self.imw, self.imh))
            self.tk_im = ImageTk.PhotoImage(self.im)
            self.canvas.create_image(0, 0, anchor='nw', image=self.tk_im)
    
        def resize_canvas(self, _event) -> None:
            '''Dynamically resize the canvas as the window changes'''
            # subtracting 20 from the width & height accommodates the scrollbars
            self.canvas.configure(
                width=self.winfo_width() - 20,
                height=self.winfo_height() - 20,
            )
    
    
    if __name__ == "__main__":
        root = ExampleApp()   # instantiate your main app class
        root.mainloop()  # start the tkinter event loop