Two tkinter Scrollbars conflict: the first scrolls correctly and the second does not

Question:

I have a tabcontrol where the scrollbars of Tab 2.1 and Tab 2.2 conflict.

Tab 2.2 scrollbar scrolls vertically correctly. However, Tab 2.1‘s scrollbar doesn’t scroll.

How can I solve the problem?

from tkinter import ttk
import tkinter as tk

window = tk.Tk() 
window.attributes('-zoomed', True)

style = ttk.Style(window)

tabControl = ttk.Notebook(window, style='Custom.TNotebook', width=700, height=320)
tabControl.place(x=1, y=1)

#TAB 1
main = ttk.Notebook(tabControl)
tabControl.add(main, text ='Tab 1')

#TAB 2
tab2 = ttk.Notebook(main)
main.add(tab2, text="Tab 2")

##TAB 2.1
a = ttk.Frame(tab2)
tab2.add(a, text="Tab 2.1")

canvas = tk.Canvas(a)

scrollbar = ttk.Scrollbar(a, orient="vertical", command=canvas.yview)
scrollable_frame = ttk.Frame(canvas, width = 800, height = 800)

scrollable_frame.bind(
    "<Configure>",
    lambda e: canvas.configure(
        scrollregion=canvas.bbox("all")
    )
)

canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
canvas.configure(yscrollcommand=scrollbar.set)

combo1=ttk.Combobox(scrollable_frame, width = 18)
combo1.place(x=20, y=20)
combo1['value'] = ["text1", "text2"]

canvas.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")

##TAB 2.2
b = ttk.Frame(tab2)
tab2.add(b, text="Tab 2.2")

canvas = tk.Canvas(b)

scrollbar = ttk.Scrollbar(b, orient="vertical", command=canvas.yview)
scrollable_frame = ttk.Frame(canvas, width = 800, height = 800)

scrollable_frame.bind(
    "<Configure>",
    lambda e: canvas.configure(
        scrollregion=canvas.bbox("all")
    )
)

canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
canvas.configure(yscrollcommand=scrollbar.set)

combo1=ttk.Combobox(scrollable_frame, width = 18)
combo1.place(x=20, y=20)
combo1['value'] = ["text1", "text2"]


canvas.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")

window.mainloop()
Asked By: Evangelos Dellas

||

Answers:

Since you have used same variable canvas for the two canvases, so canvas inside the two binding callbacks will reference the last one (inside tab 2.2).

You can use e.widget.master to reference the correct canvas inside the two binding callbacks:

scrollable_frame.bind(
    "<Configure>",
    lambda e: e.widget.master.configure(
        scrollregion=e.widget.master.bbox("all")
    )
)

Note that e.widget refers to the scrollable_frame trigger the event and so e.widget.master refers to the parent of that scrollable_frame which is the canvas.

Or simply use different variable names for the two canvases.

Answered By: acw1668