TKINTER - I have a simple GUI which makes use of some tabControl tabs. I would like to make the contents of a tab (multiple widgets) scrollable. I have figured out how to make an entire window with several widgets scrollable using a window inside a canvas, as proposed by many SO-users and other websites. However, if I try this technique with the contents of a tabControl tab, it does not work.
reprex:
from tkinter import *
from tkinter import ttk
import tkinter as tk
# main window
window = tk.Tk()
window.geometry('400x400')
tabControl = ttk.Notebook(window)
# create tabs
tab_A = ttk.Frame(tabControl)
tab_B = ttk.Frame(tabControl)
tab_C = ttk.Frame(tabControl)
tabControl.add(tab_A, text='A')
tabControl.add(tab_B, text='B')
tabControl.add(tab_C, text='C')
tabControl.grid()
# tab A
for i in range(5):
dir_frame = LabelFrame(tab_A, text=f'LabelFrame {i}', pady=3, padx=5, relief='solid', highlightthickness=5, font=100, fg='darkblue')
dir_frame.grid(column=0, row=i, columnspan=2, sticky='ew')
Label(master=dir_frame, text="Text text \t\t\t").grid(row=0, column=0, sticky='w', pady=15)
Button(master=dir_frame, text="Button").grid(row=0, column=1, sticky='e', padx=5)
# tab B
for i in range(7):
Label(master=tab_B, text=f"Text {i}\t\t\t\t").grid(row=i, column=0, sticky='w', pady=18)
chb2 = Checkbutton(tab_B).grid(row=i, column=1, sticky='e', padx=15)
# tab C
scroll = Scrollbar(tab_C)
scroll.grid(column=1, sticky='ns')
text = Text(tab_C, width=45, wrap=WORD, yscrollcommand=scroll.set)
for i in range(5):
text.insert(END, f'\n{i}.\n')
text.insert(END, f'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.')
text.insert(END, f'\n\n\n\n')
text.grid(column=0, row=0, sticky="nesw")
text.configure(state=DISABLED)
scroll.config(command=text.yview)
# run
window.mainloop()
So if I create a main frame and canvas with scrollbar, configure this canvas, create another frame inside the canvas and add that new frame to a window in the canvas (which seems to be the way to do it), it is scrollable but shows up below my tab. Besides, the tab function does not show/hide the content anymore.
This is my code:
from tkinter import *
from tkinter import ttk
import tkinter as tk
# main window
window = tk.Tk()
window.geometry('400x400')
tabControl = ttk.Notebook(window)
# create tabs
tab_A = ttk.Frame(tabControl)
tab_B = ttk.Frame(tabControl)
tab_C = ttk.Frame(tabControl)
tabControl.add(tab_A, text='A')
tabControl.add(tab_B, text='B')
tabControl.add(tab_C, text='C')
tabControl.grid()
# create a main frame
main_frame = Frame(window)
main_frame.columnconfigure(0, weight=1)
main_frame.grid(column=0, row=1, sticky='nsew')
# create a canvas
my_canvas = Canvas(main_frame)
my_canvas.grid(column=0, row=1, sticky='nsew')
# add a scrollbar to the canvas
my_scrollbar = ttk.Scrollbar(main_frame, orient=VERTICAL, command=my_canvas.yview)
my_scrollbar.grid(column=0, row=1, sticky='ens')
# configure the canvas
my_canvas.configure(yscrollcommand=my_scrollbar.set)
my_canvas.bind('<Configure>', lambda e: my_canvas.configure(scrollregion=my_canvas.bbox("all")))
# create another frame inside the canvas
second_frame = Frame(my_canvas)
# add that new frame to a window in the canvas
my_canvas.create_window((0,0), window=second_frame, anchor="nw")
# tab A
for i in range(5):
dir_frame = LabelFrame(second_frame, text=f'LabelFrame {i}', pady=3, padx=5, relief='solid', highlightthickness=5, font=100, fg='darkblue')
dir_frame.grid(column=0, row=i, columnspan=2, sticky='ew')
Label(master=dir_frame, text="Text text \t\t\t").grid(row=0, column=0, sticky='w', pady=15)
Button(master=dir_frame, text="Button").grid(row=0, column=1, sticky='e', padx=5)
# tab B
for i in range(7):
Label(master=tab_B, text=f"Text {i}\t\t\t\t").grid(row=i, column=0, sticky='w', pady=18)
chb2 = Checkbutton(tab_B).grid(row=i, column=1, sticky='e', padx=15)
# tab C
scroll = Scrollbar(tab_C)
scroll.grid(column=1, sticky='ns')
text = Text(tab_C, width=45, wrap=WORD, yscrollcommand=scroll.set)
for i in range(5):
text.insert(END, f'\n{i}.\n')
text.insert(END, f'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.')
text.insert(END, f'\n\n\n\n')
text.grid(column=0, row=0, sticky="nesw")
text.configure(state=DISABLED)
scroll.config(command=text.yview)
# run
window.mainloop()
Tab C, which contains only a text widget, functions like I would like to have A en B too. It is scrollable and the tabs functions like a tab.
Any suggestions?
CodePudding user response:
You've put the canvas in the main frame rather than in a tab. If you want it to be in a tab, it needs to be a child of the frame for a tab.
main_frame = Frame(tab_A)
# ^^^^^
Unrelated to the question that was asked, I recommend using pack
rather than grid
for widgets that are the only child, or one of only a couple of children in a containing widget. It requires a little bit less code and is a bit more foolproof since you don't have to worry about adding weights to the only row and column.
For example, it takes a single line of code to get the notebook to fill the window and to grow and shrink as it resizes:
tabControl.pack(fill="both", expand=True)
The same is true for main_frame
since it's the only widget in the tab frame.
main_frame.pack(fill="both", expand=True)
And finally, pack
also makes laying out a widget and it's scrollbar very easy:
my_scrollbar.pack(side="right", fill="y")
my_canvas.pack(side="left", fill="both", expand=True)