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