0
votes

The following code creates a canvas with a frame inside. I am using the canvas to enable the addition of a vertical scrollbar, which appears as necessary. I have coloured the various sections - root, blue; window, green; canvas, red and frame, cyan. From this it can be seen that window completely fills root (no blue seen). However, canvas only fills window in the vertical direction (green visible to the rhs on expanding the window, and frame only fills canvas in the horizontal direction (red visible below cyan). I can't see what is causing the problem. Frame is bound to canvas and canvas has sticky='nsew' set so should be filling window.

import Tkinter as tk
import tkFileDialog

class AutoScrollbar(tk.Scrollbar):
    # a scrollbar that hides itself if it's not needed.  only
    # works if you use the grid geometry manager.
    def set(self, lo, hi):
        if float(lo) <= 0.0 and float(hi) >= 1.0:
            # grid_remove is currently missing from Tkinter!
            self.tk.call("grid", "remove", self)
        else:
            self.grid()
        tk.Scrollbar.set(self, lo, hi)
    def pack(self, **kw):
        raise TclError, "cannot use pack with this widget"
    def place(self, **kw):
        raise TclError, "cannot use place with this widget"

class Window(tk.Frame):
  def UserInput(self,status,name):
    row = self.row
    optionLabel = tk.Label(self.frame)
    optionLabel["text"] = name
    optionLabel.grid(row=row, column=0, sticky='w')
    var = tk.StringVar(root)
    var.set(status)
    w = tk.Entry(self.frame, textvariable= var)
    w.grid(row=row, column=1, sticky='ew')
    self.grid_columnconfigure(1,weight=1)
    self.row += 1
    return w

  def on_canvas_resize(self,event):
    padding = 8
    width = self.canvas.winfo_width() - padding
    self.canvas.itemconfigure("frame", width=width)

  def OnFrameConfigure(self, event):
    self.canvas.configure(scrollregion=self.canvas.bbox("all"))

  def __init__(self,parent):
    tk.Frame.__init__(self,parent)

    self.grid_rowconfigure(0, weight=1)
    self.grid_columnconfigure(0,weight=1)

    self.vscrollbar = AutoScrollbar(self,orient = tk.VERTICAL)
    self.vscrollbar.grid(row = 0,column = 3, sticky = 'ns')

    self.canvas = tk.Canvas(self, yscrollcommand = self.vscrollbar.set,bg='red')
    self.canvas.grid(row=0, column=0, sticky='nsew')
    self.canvas.grid_rowconfigure(0, weight = 1)
    self.canvas.grid_columnconfigure(0, weight = 1)

    self.frame = tk.Frame(self.canvas, bg='cyan')
    self.frame.bind("<Configure>", self.OnFrameConfigure)

    self.frame.grid_rowconfigure(0, weight=1)
    self.frame.grid_columnconfigure(0,weight=1)
    self.frame.grid_columnconfigure(1,weight=3)

    self.vscrollbar.config(command=self.canvas.yview) 

    self.canvas.create_window(0, 0, anchor = tk.NW, window= self.frame, tags =["frame"])
    self.canvas.bind("<Configure>", self.on_canvas_resize)

    self.row = 0

    for i in range(10):
      self.Number = self.UserInput("1", "number")

if __name__ == "__main__":
  root = tk.Tk()
  root.configure(background='blue')  
  root.grid_columnconfigure(0, weight=1)
  root.grid_rowconfigure(0,weight=1)  
  window = Window(root)
  window.configure(background='green')
  window.grid(row=0,column=0,sticky='nsew')
  root.mainloop()
1

1 Answers

1
votes

You are putting the canvas in column 0 (zero), and you are properly giving that column a weight. However, you are also giving an equal weight to column 1 (one) (see line 29), which prevents the canvas from filling the window. Remove line 29, which is setting the weight of column 1 to 1.

Your frame fills the canvas horizontally because that is what you are telling it to do. If you want it to also be the same height you will need to set its height, too.