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

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


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 windowsclass 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()


You can use the .pack geometry manager:

self.c=Canvas(…)self.c.pack(fill="both", expand=True)

should do the trick.If your canvas is inside a frame, do the same for the frame:

self.r = rootself.f = Frame(self.r)self.f.pack(fill="both", expand=True)self.c = Canvas(…)self.c.pack(fill="both", expand=True)

See effbot for more info.

Edit: if you don't want a "full sized" canvas, you can bind your canvas to a function:

self.c.bind('<Configure>', self.resize)def resize(self, event):    w,h = event.width-100, event.height-100    self.c.config(width=w, height=h)

See effbot again for events and bindings


To resize the canvas object to fit the new window size just use the tkinter geometry managers properly.

With pack theres the expand and fill options, with grid you will need to use the columnconfigure and rowconfigure methods of the canvas master (the widget that contains the canvas) and with place manager theres the relwidth and relheight options.On the other hand, this only resizes the canvas dimensions without changing the dimensions of its objects. To resize the canvas objects you will need to use the scale method as has been suggested. Another thing to take into consideration is that some canvas objects like text will not be affected by the scale canvas method.

Here is the response code changed a little bit:

import tkinter as tk# a subclass of Canvas for dealing with resizing of windowsclass ResizingCanvas(tk.Canvas):    def __init__(self, parent, **kwargs):        tk.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 = event.width/self.width        hscale = event.height/self.height        self.width = event.width        self.height = event.height        # rescale all the objects        self.scale("all", 0, 0, wscale, hscale)def main():    root = tk.Tk()    myframe = tk.Frame(root)    myframe.pack(fill=tk.BOTH, expand=tk.YES)    mycanvas = ResizingCanvas(myframe,width=850, height=400, bg="light blue")#, highlightthickness=0)    mycanvas.pack(fill=tk.BOTH, expand=tk.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    root.mainloop()if __name__ == "__main__":    main()