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()
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.
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()
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.