Search code examples
pythoncanvaspython-3.xtkinterautoresize

How to get tkinter canvas to dynamically resize to window width?


I need to get a canvas in tkinter to set its width to the width of the window, and then dynamically re-size the canvas when the user makes the window smaller/bigger.

Is there any way of doing this (easily)?


Solution

  • I thought I would add in some extra code to expand on @fredtantini's answer, as it doesn't deal with how to update the shape of widgets drawn on the Canvas.

    To do this you need to use the scale method and tag all of the widgets. A complete example is below.

    from Tkinter import *
    
    # a subclass of Canvas for dealing with resizing of windows
    class ResizingCanvas(Canvas):
        def __init__(self,parent,**kwargs):
            Canvas.__init__(self,parent,**kwargs)
            self.bind("<Configure>", self.on_resize)
            self.height = self.winfo_reqheight()
            self.width = self.winfo_reqwidth()
    
        def on_resize(self,event):
            # determine the ratio of old width/height to new width/height
            wscale = float(event.width)/self.width
            hscale = float(event.height)/self.height
            self.width = event.width
            self.height = event.height
            # resize the canvas 
            self.config(width=self.width, height=self.height)
            # rescale all the objects tagged with the "all" tag
            self.scale("all",0,0,wscale,hscale)
    
    def main():
        root = Tk()
        myframe = Frame(root)
        myframe.pack(fill=BOTH, expand=YES)
        mycanvas = ResizingCanvas(myframe,width=850, height=400, bg="red", highlightthickness=0)
        mycanvas.pack(fill=BOTH, expand=YES)
    
        # add some widgets to the canvas
        mycanvas.create_line(0, 0, 200, 100)
        mycanvas.create_line(0, 100, 200, 0, fill="red", dash=(4, 4))
        mycanvas.create_rectangle(50, 25, 150, 75, fill="blue")
    
        # tag all of the drawn widgets
        mycanvas.addtag_all("all")
        root.mainloop()
    
    if __name__ == "__main__":
        main()