0

I'm working on a tkinter application and I use the following code for vertical notebooks.

self.style = ttk.Style(self.window)
self.style.configure('lefttab.TNotebook', tabposition='wn')

However, I want to be able to scroll through these notebooks vertically. I'd like to be able to use a Notebook just like any normal notebook, only that you're able to use a scrollbar to scroll down through different menu options. I've done research but I couldn't find any vertical scrollbars, nor have I found success trying to make a scrollbar myself.

Thanks.

j_4321
  • 15,431
  • 3
  • 34
  • 61
Corman
  • 749
  • 11
  • 16

2 Answers2

2

The idea is to create a VertNotebook class which is a frame containing a scrollbar and a listbox for the tabs. You can bind the '<<ListboxSelect>>' event to a function displaying the widget associated with the tab to mimick the behavior of a ttk.Notebook. Here is the code:

import tkinter as tk
from tkinter import ttk


class VertNotebook(ttk.Frame):
    def __init__(self, *args, **kw):
        ttk.Frame.__init__(self, *args, **kw)
        self.rowconfigure(0, weight=1)
        self.columnconfigure(2, weight=1)
        # scrollable tabs
        self._listbox = tk.Listbox(self, width=1, background='lightgrey', 
                                   highlightthickness=0, relief='raised')
        scroll = ttk.Scrollbar(self, orient='vertical', command=self._listbox.yview)
        self._listbox.configure(yscrollcommand=scroll.set)

        # list of widgets associated with the tabs
        self._tabs = []
        self._current_tab = None  # currently displayed tab

        scroll.grid(row=0, column=0, sticky='ns')
        self._listbox.grid(row=0, column=1, sticky='ns')
        # binding to display the selected tab
        self._listbox.bind('<<ListboxSelect>>', self.show_tab)

    def add(self, widget, label): # add tab
        self._listbox.insert('end', label)  # add label listbox
        # resize listbox to be large enough to show all tab labels
        self._listbox.configure(width=max(self._listbox.cget('width'), len(label)))
        if self._current_tab is not None:
            self._current_tab.grid_remove()
        self._tabs.append(widget)
        widget.grid(in_=self, column=2, row=0, sticky='ewns')
        self._current_tab = widget
        self._listbox.selection_clear(0, 'end')
        self._listbox.selection_set('end')
        self._listbox.see('end')

    def show_tab(self, event):
        print(event, self._listbox.curselection(), )
        try:
            widget = self._tabs[self._listbox.curselection()[0]]
            print(widget)
        except IndexError:
            return
        if self._current_tab is not None:
            self._current_tab.grid_remove()
        self._current_tab = widget
        widget.grid(in_=self, column=2, row=0, sticky='ewns')


root = tk.Tk()
nb = VertNotebook(root)
for i in range(50):
    nb.add(ttk.Label(nb, text='Label %i' % i), 'Tab %i' % i)
nb.pack(expand=True, fill='both')
root.mainloop()
j_4321
  • 15,431
  • 3
  • 34
  • 61
  • This is great! The only change I made is that I added an option for me to change the width and height. – Corman Mar 19 '20 at 15:13
1

Finally got a correct way to do this. Only tabposition is not enough if the labels have different sizes.

See this other answer: https://stackoverflow.com/a/76007959/12287472