When trying to use the ttk.Scrollbar feature, my frame won't expand to fill the canvas even with expand=True. I have found similar issues on other posts however the solutions they used aren't fixing my problem.
Here is a simplified version of my code to show the issue. I essentially want the pink area to fill the entire canvas.
import tkinter as tk
from tkinter import ttk
class MyView(tk.Tk):
def __init__(self):
super().__init__()
self.title("Any help is appreciated :)")
self.geometry("600x300")
self.container = OuterFrame(self)
self.container.pack(expand=1, fill="both")
class OuterFrame(tk.Frame):
def __init__(self, container):
super().__init__(container)
#CONTAINERS
self.canvas = tk.Canvas(self)
self.canvas.pack(side="left", expand=1, fill="both")
self.scrollbar = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
self.scrollbar.pack(side="right", fill="y")
self.canvas.config(yscrollcommand=self.scrollbar.set)
self.canvas_id = tk.Frame(self.canvas)
self.canvas_id.bind("<Configure>", lambda e: self.canvas.config(scrollregion=self.canvas.bbox("all")))
self.canvas.create_window((0,0), window=self.canvas_id, anchor="nw")
self.container = InnerFrame(self.canvas_id)
self.container.pack(expand=1, fill="both")
class InnerFrame(tk.Frame):
def __init__(self, container):
super().__init__(container)
self.config(bg="pink")
self.titles = ["test1", "test2", "test3", "test4", "test5", "test6"]
self.label = tk.Label(self, text="Objectives")
self.label.pack(pady=5)
self.checkvars = {} #for the ckeckbuttons
self.frames = {}
for title in self.titles:
self.checkvars[title] = tk.IntVar()
self.frames[title] = InnerFrameObjective(self, title, self.checkvars[title])
self.frames[title].pack(expand=1, fill="x", pady=(0,15))
class InnerFrameObjective(tk.Frame):
def __init__(self, container, string, checkvar):
super().__init__(container)
self.configure(pady=4, padx=30, bg="pink")
self.title = string
self.Framelabels = InnerFrameObjectiveLabels(self)
self.Framelabels.pack(side="left", expand=1, fill="both")
self.checkbutton = tk.Checkbutton(self, variable=checkvar, onvalue=1, offvalue=0, bg="blue")
self.checkbutton.pack(side="right", expand=1, fill="both")
class InnerFrameObjectiveLabels(tk.Frame):
def __init__(self, container):
super().__init__(container)
self.parent = container
self.config(bg="blue")
self.title = self.parent.title
self.due_date = None
self.label = tk.Label(self, text=self.title, bg="blue")
self.label.pack()
self.label2 = tk.Label(self, text="Due Date:", bg="blue")
self.label2.pack(anchor="w")
a = MyView()
CodePudding user response:
There are a few things to note here:
The
self.canvas_id
will only grow as much as the space needed by its children, unless told not to (withpack_propagate(0)
and need to give in the dimensions)You are manually setting dimension on the main window, which in turn will make the
self.canvas
grow to fill that dimension since you are usingpack(side="left", expand=1, fill="both")
onself.canvas
.-
my frame won't expand to fill the canvas even with expand=True
Your frame
self.container
will not expand the entire size ofself.canvas
as it can only grow as much as its parent (self.canvas_id
), which also does not grow as much as the canvas unless told to do so. Also sinceself.canvas_id
is awindow
inside the canvas, you cannot make it grow withpack
like you expect, you will have to fire up an event each time the canvas changes size and change the frame size to match the size of the canvas. Now another problem arises when you use
pack_propagate(0)
, which makes it a problem to get theheight
ofself.container
to set for the frame to outgrow the current size of canvas (only then the scrolling will work properly). To tackle this, rather than usingpack_propagate(0)
and changing the size ofself.canvas_id
directly, we will configure its size onself.canvas
instead.
self.canvas.create_window((0,0), window=self.canvas_id, anchor="nw", tags='window') # Add a tag
self.canvas.bind('<Configure>', lambda e: self.canvas.itemconfig('window', width=e.width)) # Use that tag to identify that window and change the size
The explanation kind of assumes you know nothing, so it goes in some concepts that may seem hard to understand.