Rodney Boyd
Rodney Boyd

Reputation: 39

Scrollbar on tkinter canvas/frame not working

I adapted the solution by Bryan Oakley at Adding a scrollbar to a group of widgets in Tkinter to implement a scrollbar on a tkinter Frame. (The code reads key/value pairs from a dict and generates a series of editable entries in table format, prefaced by a checkbox that enables the user to delete entries.) I can get his code working but not my own: the scrollbar is present but does not become enabled. The background colors suggest that the canvas is expanding just as the frame is, which would explain why no working scrollbar, but I don't know why the canvas expands. Any suggestions? Thanks.

def make_table(map, widget, prefix):
    
    
    delete_label_str = StringVar()
    delete_label_str.set('Delete')
    delete_label = tk.Label(widget, textvariable=delete_label_str, width=6, height=1, justify=tk.CENTER)
    delete_label.grid(row=0, column=0)
    abbrev_label_str = StringVar()
    abbrev_label_str.set('Name')
    abbrev_label = tk.Label(widget, textvariable=abbrev_label_str, height=1, width=6, justify=tk.CENTER)
    abbrev_label.grid(row=0, column=1)
    def_label_str = StringVar()
    def_label_str.set('Definition')
    def_label = tk.Label(widget, textvariable=def_label_str, height=1, width=45, justify=tk.LEFT)
    def_label.grid(row=0, column=2)
    
    
    if not map or len(map) == 0:
        return
    row_num = 1
    for key in map.keys():
        delete_var_name = prefix + str(row_num)
        globals()[delete_var_name] = BooleanVar()
        globals()[delete_var_name].set(False)
        delete_checkbox = tk.Checkbutton(widget, variable=globals()[delete_var_name], height=1, anchor=tk.W)
        delete_checkbox.grid(row=row_num, column=0)
        e1 = tk.Entry(widget, width=6, )
        e1.grid(row=row_num, column=1)
        e1.insert(END, key)

        e2 = tk.Entry(widget, width=45, )
        e2.grid(row=row_num, column=2)
        e2.insert(END, map[key])
        row_num+=1
    

def onFrameConfigure(canvas):
    #Reset the scroll region to encompass the inner frame
    canvas.configure(scrollregion=canvas.bbox("all"))
    

def show_abbrevs():
    dlog = tk.Toplevel(root)
    dlog.title('Abbreviations')
    dlog.geometry('425x325')
    delete_prefix = 'delete_abbr_value'
    global cur_path
    if cur_path:
        basepath = os.path.splitext(cur_path)[0]
        fname = basepath + '.abb'
    else:  
        fname = my_path + '/picardy.abb'
    canvas = tk.Canvas(dlog, borderwidth=0, background="blue")
    table_frame = tk.Frame(canvas, pady=10, padx=5, background="yellow")
    vsb = tk.Scrollbar(dlog, orient="vertical", command=canvas.yview, )
    canvas.configure(yscrollcommand=vsb.set)

    vsb.pack(side="right", fill="y")
    canvas.pack(side="top", fill="both", expand=True)
    canvas.create_window((4,4), window=table_frame, anchor="nw")

    table_frame.bind("<Configure>", lambda event, canvas=canvas:onFrameConfigure(canvas))
      
    table_frame.pack()
    #table_frame.focus_set()
    
    make_table(abbrev_map, table_frame, delete_prefix)
    button_frame = tk.Frame(dlog, pady=10)
    
    new = tk.Button(button_frame, text="Add", width=10, height=1, command=lambda:add_entry(table_frame, delete_prefix))
    new.grid(row=0, column=0, sticky="ew", padx=5, pady=5)
    delete = tk.Button(button_frame, text="Delete", width=10, height=1, command=lambda:delete_entries(table_frame, delete_prefix))
    delete.grid(row=0, column=1, sticky="ew", padx=5, pady=5)
    save = tk.Button(button_frame, text="Save", width=10, height=1, command=lambda:save_entries(table_frame, fname, delete_prefix))
    save.grid(row=0, column=2, sticky="ew", padx=5, pady=5)
    button_frame.pack()

Upvotes: 1

Views: 417

Answers (1)

Mahmoud Magdy
Mahmoud Magdy

Reputation: 921

I used your code in simple example and worked when used scrollregion arugment in canvas

# 1200 is the max height, scroll can reach
scrollregion=(0,0,0,1200)

# example

import tkinter as tk
root= tk.Tk()
canvas1 = tk.Canvas(root, width = 75*3, height = (50*20)+50, scrollregion=(0,0,0,1200))

table_frame = tk.Frame(canvas1, pady=10, padx=5, background="yellow")
vsb = tk.Scrollbar(root, orient="vertical", command=canvas1.yview, )
canvas1.configure(yscrollcommand=vsb.set)

vsb.pack(side="right", fill="y")
canvas1.pack(side="top", fill="both", expand=True)
canvas1.create_window((4,4), window=table_frame, anchor="nw")

i was creating small dynamic helper functions to create grid with unlimited rows and max 3 cols you can test the scroll in this example full code and grid Drawer function

https://github.com/MahmoudHegazi/tkinter_grid_lib

Upvotes: 0

Related Questions