python tkinter canvas not resizing -


i'm trying subclass tkinter controls make auto scrolling frame use in program, want scroll vertically, , when widgets added need scroll horizontally instead resize parent fit. widgets go in frame not defined @ runtime , created dynamically, must react events. have code partly working, in run it, can use buttons @ bottom add , remove labels on fly, if without manually resizing window first works expected. if manually resize window horizontal resizing stops working:

from tkinter import *  __all__ = ["verticalscrolledframe"]  class verticalscrolledframe(frame):     def __init__(self, parent, *args, **kw):         frame.__init__(self, parent, *args, **kw)                     self.grid_columnconfigure(1, weight=1)         self.grid_rowconfigure(1, weight=1)         # create canvas object , vertical scrollbar scrolling         self.vscrollbar = scrollbar(self, orient=vertical)         self.vscrollbar.grid(column=2, row=1, sticky="nesw")         self.canvas = canvas(self, bd=0, highlightthickness=0, yscrollcommand=self.vscrollbar.set, height=10, width=10)         self.canvas.grid(column=1, row=1, sticky="nesw")         self.vscrollbar.config(command=self.canvas.yview)          # reset view         self.canvas.xview_moveto(0)         self.canvas.yview_moveto(0)          # create frame inside canvas scrolled         self.interior = frame(self.canvas)         self.interior_id = self.canvas.create_window(0, 0, window=self.interior, anchor=nw)          self.interior.bind('<configure>', self._configure_interior)          # track changes canvas , frame width , sync them,         # updating scrollbar     def _configure_interior(self, event=none):         print("config interior")         # update scrollbars match size of inner frame         size = (self.interior.winfo_width(), self.interior.winfo_height())         self.canvas.config(scrollregion="0 0 %s %s" % size)         if self.interior.winfo_reqwidth() > self.canvas.winfo_width():             # update canvas's width fit inner frame             self.canvas.config(width=self.interior.winfo_reqwidth())  if __name__ == "__main__":     labels = []     labels2 = []     def add1():         l = label(f.interior, text=str(len(labels)+1))         l.grid(column=len(labels)+1, row=1)         labels.append(l)      def remove1():         l = labels.pop()         l.grid_forget()         l.destroy()      def add2():         l = label(f.interior, text=str(len(labels2)+1))         l.grid(column=1, row=len(labels2)+1)         labels2.append(l)      def remove2():         l = labels2.pop()         l.grid_forget()         l.destroy()      app = tk()     app.grid_columnconfigure(1, weight=1)     app.grid_columnconfigure(2, weight=1)     app.grid_rowconfigure(1, weight=1)     f = verticalscrolledframe(app)     f.grid(column=1, row=1, columnspan=2, sticky="nesw")     button(app, text="add-h", command=add1).grid(column=1, row=2, sticky="nesw")     button(app, text="remove-h", command=remove1).grid(column=2, row=2, sticky="nesw")     button(app, text="add-v", command=add2).grid(column=1, row=3, sticky="nesw")     button(app, text="remove-v", command=remove2).grid(column=2, row=3, sticky="nesw")     app.mainloop() 

i'm working solely on windows , using python 3.3, tried 3.4 no change.

why resizing window stop call to:

self.canvas.config(width=self.interior.winfo_reqwidth()) 

from working?

edit: brian oakley's response makes sense can understand behavior, have changed code handle changes canvas size when window resized:

from tkinter import *  __all__ = ["verticalscrolledframe"]  class verticalscrolledframe(frame):     def __init__(self, parent, *args, **kw):         frame.__init__(self, parent, *args, **kw)         p = parent         while true:             if p.winfo_class() in ['tk', 'toplevel']:                 break             else:                 p = self._nametowidget(p.winfo_parent())         self.root_window = p         self.grid_columnconfigure(1, weight=1)         self.grid_rowconfigure(1, weight=1)         # create canvas object , vertical scrollbar scrolling         self.vscrollbar = scrollbar(self, orient=vertical)         self.vscrollbar.grid(column=2, row=1, sticky="nesw")         self.canvas = canvas(self, bd=0, highlightthickness=0, yscrollcommand=self.vscrollbar.set, height=10, width=10)         self.canvas.grid(column=1, row=1, sticky="nesw")         self.vscrollbar.config(command=self.canvas.yview)          # reset view         self.canvas.xview_moveto(0)         self.canvas.yview_moveto(0)          # create frame inside canvas scrolled         self.interior = frame(self.canvas)         self.interior_id = self.canvas.create_window(0, 0, window=self.interior, anchor=nw)          self.interior.bind('<configure>', self._configure_interior)          self.canvas.bind('<configure>', self._configure_canvas)          # track changes canvas , frame width , sync them,         # updating scrollbar     def _configure_interior(self, event=none):         print("config interior")         # update scrollbars match size of inner frame         size = (self.interior.winfo_width(), self.interior.winfo_height())         self.canvas.config(scrollregion="0 0 %s %s" % size)         if self.interior.winfo_reqwidth() >= self.canvas.winfo_width():             # update canvas's width fit inner frame             # works before mainloop             self.canvas.config(width=self.interior.winfo_reqwidth())         screen_h = self.winfo_screenheight()         if ((self.root_window.winfo_rooty() + self.root_window.winfo_height() - self.canvas.winfo_height() + self.interior.winfo_reqheight()) < screen_h):             self.canvas.configure(height=self.interior.winfo_reqheight())      def _configure_canvas(self, event=none):         print("config canvas")         if self.interior.winfo_reqwidth() < self.canvas.winfo_width():             self.canvas.itemconfigure(self.interior_id, width=self.canvas.winfo_width())         elif self.interior.winfo_reqwidth() > self.canvas.winfo_width():             self.canvas.config(width=self.interior.winfo_reqwidth())          if (self.interior.winfo_reqheight() < self.canvas.winfo_height()) or (self.interior.winfo_height() < self.canvas.winfo_height()):             self.canvas.itemconfigure(self.interior_id, height=self.canvas.winfo_height())  if __name__ == "__main__":     labels = []     labels2 = []     def add1(): ##        app.geometry("")         l = label(f.interior, text=str(len(labels)+1))         l.grid(column=len(labels)+1, row=1)         f.interior.grid_columnconfigure(len(labels)+1, weight=1, minsize=l.winfo_reqwidth())         labels.append(l)      def remove1(): ##        app.geometry("")         l = labels.pop()         l.grid_forget()         f.interior.grid_columnconfigure(len(labels)+2, weight=0, minsize=0)         l.destroy()      def add2():         l = label(f.interior, text=str(len(labels2)+1))         l.grid(column=1, row=len(labels2)+1)         f.interior.grid_rowconfigure(len(labels2)+1, weight=1, minsize=l.winfo_reqheight())         labels2.append(l)      def remove2():         l = labels2.pop()         l.grid_forget()         f.interior.grid_rowconfigure(len(labels2)+2, weight=0, minsize=0)         l.destroy()      app = tk()     app.grid_columnconfigure(1, weight=1)     app.grid_columnconfigure(2, weight=1)     app.grid_rowconfigure(1, weight=1)     f = verticalscrolledframe(app)     f.grid(column=1, row=1, columnspan=2, sticky="nesw")     button(app, text="add-h", command=add1).grid(column=1, row=2, sticky="nesw")     button(app, text="remove-h", command=remove1).grid(column=2, row=2, sticky="nesw")     button(app, text="add-v", command=add2).grid(column=1, row=3, sticky="nesw")     button(app, text="remove-v", command=remove2).grid(column=2, row=3, sticky="nesw")     in range(0,10):         add1()         add2()     app.mainloop() 

the problem seeing if add items vertically before resizing window, _configure_interior function called each widget gets added , window either resized vertically fit (if before window sizing) , supposed update scrollregion (and scrollbar) if not, after resizing window _configure_interior stops being called each widget added, , if call manually scrollbar still not updated?

why resizing window stop call to:

self.canvas.config(width=self.interior.winfo_reqwidth())

that because code bound frame changing. when user resizes window, resize window, not frame. if want function called when window resized must bind or similar function resizing of window or canvas in addition automatic resizing of interior frame.

you'll need aware if user resizes window, adding objects frame in canvas won't make window bigger. user's choice of window size override computed size interior widgets being resized. you'll have reset geometry empty string automatically grow.


Comments

Popular posts from this blog

java - Run spring boot application error: Cannot instantiate interface org.springframework.context.ApplicationListener -

reactjs - React router and this.props.children - how to pass state to this.props.children -

Excel VBA "Microsoft Windows Common Controls 6.0 (SP6)" Location Changes -