1

Problem:

I made a scrollable canvas in tkinter but it isn't filling the whole canvas horizontally. I've tried adding weight = 1 and columnspan = 2 and other arguments when gridding but can't get it to fill properly. How can I make the widget span across the whole x axis?

Code:

from tkinter import *
from tkinter import ttk
import time

WIN_WIDTH = 800
WIN_HEIGHT = 600
PRIMARY_COLOUR = "#5AC1D0"
SECONDARY_COLOUR = "#7FDCA5"
FONT = "Courier"

class Display:
    def __init__(self, tinstance):
        __all__ = ["createDisplay", "updateDisplay", "destoryDisplay"]
        self.tinstance = tinstance
        
    def createDisplay(self, winresx, winresy, wintitle, useicon, iconpath):
        self.tinstance.geometry("{}x{}+{}+{}".format(winresx, winresy, int(winresx / 2), int(winresy / 7)))
        self.tinstance.title(wintitle)
        #self.tinstance.resizable(0, 0)
        self.tinstance.wm_attributes("-topmost", 1)
        if useicon == True:
            self.tinstance.call("wm", "iconphoto", self.tinstance._w, PhotoImage(file = iconpath))
        
    def updateDisplay(self):
        while True:
            try:
                self.tinstance.update_idletasks()
                self.tinstance.update()
                time.sleep(0.01)
            except TclError:
                pass
            
    def destroyDisplay(self):
        self.tinstance.destroy()

if __name__ == "__main__":
    tk = Tk()
    display = Display(tk)
    display.createDisplay(WIN_WIDTH, WIN_HEIGHT, "Julie's Party Hire Store", True, "ico.png")
    
    canvas = Canvas(tk, bg = PRIMARY_COLOUR, width = WIN_WIDTH, height = WIN_HEIGHT).grid(row = 0, column = 0)
    title = Label(tk, text = "Welcome to Julie's Party Hire Store!", font = (FONT, 20), bg = SECONDARY_COLOUR)
    title.grid(row = 0, column = 0, sticky = N)

    #Scrollable window
    scroll_wrapper = Frame(canvas)
    scroll_canvas = Canvas(scroll_wrapper, bg = PRIMARY_COLOUR)
    scroll_frame = Frame(scroll_canvas)
    scroll_scrollbar = ttk.Scrollbar(scroll_wrapper, orient = "vertical", command = scroll_canvas.yview)
    
    scroll_canvas.configure(yscrollcommand = scroll_scrollbar.set)
    scroll_canvas.bind("<Configure>", lambda e: scroll_canvas.configure(scrollregion = scroll_canvas.bbox("all")))
    scroll_canvas.create_window((0, 0), window = scroll_frame)

    scroll_wrapper.grid(row = 0, column = 0, sticky = EW)    
    scroll_canvas.grid(row = 0, column = 0, sticky = EW)
    scroll_scrollbar.grid(row = 0, column = 1, sticky = NS)
    
    for i in range(1, 50):
        b = Button(scroll_frame, text = "Button " + str(i)).grid(row = i, column = 0)
    
    tk.mainloop()
JaxonReid
  • 13
  • 1
  • 5
  • Did you notice that `canvas` is `None`? Normally don't use `pack()/grid()/place()` to put widgets inside a canvas. I think that it is better to use `Frame` instead of `Canvas` for the outer container. – acw1668 Jul 06 '21 at 01:15

1 Answers1

0

Have you tried the method columnconfigure(column, weight)?

The weight determines how wide the column will occupy, which is relative to other columns.

columnconfigure(0, weight=1) and columnconfigure(1, weight=0) means that column 0 will occupy all the space relative to column 1.

Code:

from tkinter import *
from tkinter import ttk
import time

WIN_WIDTH = 800
WIN_HEIGHT = 600
PRIMARY_COLOUR = "#5AC1D0"
SECONDARY_COLOUR = "#7FDCA5"
FONT = "Courier"

class Display:
    def __init__(self, tinstance):
        __all__ = ["createDisplay", "updateDisplay", "destoryDisplay"]
        self.tinstance = tinstance
        
    def createDisplay(self, winresx, winresy, wintitle, useicon, iconpath):
        self.tinstance.geometry("{}x{}+{}+{}".format(winresx, winresy, int(winresx / 2), int(winresy / 7)))
        self.tinstance.title(wintitle)
        #self.tinstance.resizable(0, 0)
        self.tinstance.wm_attributes("-topmost", 1)
        #if useicon == True:
        #    self.tinstance.call("wm", "iconphoto", self.tinstance._w, PhotoImage(file = iconpath))
        
    def updateDisplay(self):
        while True:
            try:
                self.tinstance.update_idletasks()
                self.tinstance.update()
                time.sleep(0.01)
            except TclError:
                pass
            
    def destroyDisplay(self):
        self.tinstance.destroy()

if __name__ == "__main__":
    tk = Tk()
    display = Display(tk)
    #display.createDisplay(WIN_WIDTH, WIN_HEIGHT, "Julie's Party Hire Store", True, "ico.png")
    
    canvas = Canvas(tk, bg = PRIMARY_COLOUR, width = WIN_WIDTH, height = WIN_HEIGHT).grid(row = 0, column = 0)
    title = Label(tk, text = "Welcome to Julie's Party Hire Store!", font = (FONT, 20), bg = SECONDARY_COLOUR)
    title.grid(row = 0, column = 0, sticky = N)

    #Scrollable window
    scroll_wrapper = Frame(canvas)

    scroll_wrapper.columnconfigure(0, weight=1)
    scroll_wrapper.columnconfigure(1, weight=0)
    
    scroll_canvas = Canvas(scroll_wrapper, bg = PRIMARY_COLOUR)
    scroll_frame = Frame(scroll_canvas)
    scroll_scrollbar = ttk.Scrollbar(scroll_wrapper, orient = "vertical", command = scroll_canvas.yview)
    #ttk.Label(scroll_wrapper, text='test').grid(column=2)
    
    scroll_canvas.configure(yscrollcommand = scroll_scrollbar.set)
    scroll_canvas.bind("<Configure>", lambda e: scroll_canvas.configure(scrollregion = scroll_canvas.bbox("all")))
    scroll_canvas.create_window((0, 0), window = scroll_frame)


    scroll_wrapper.grid(row = 0, column = 0, sticky = EW)

    scroll_canvas.grid(row = 0, column = 0, sticky = EW)
    scroll_scrollbar.grid(row = 0, column = 1, sticky = NS)
    
    for i in range(1, 50):
        b = Button(scroll_frame, text = "Button " + str(i)).grid(row = i, column = 0)
    
    tk.mainloop()
Kazoe
  • 51
  • 5
  • Yes thank you that is what I was looking for. I attempted to use the column configure function but it didn't work, I must have used it wrong. Do you think you could explain how it works? – JaxonReid Jul 06 '21 at 23:40
  • Check this out: https://stackoverflow.com/questions/45847313/what-does-weight-do-in-tkinter – Kazoe Jul 07 '21 at 12:28