Notebook Widget

Manual page: ttk_notebook(3tk)

This widget is useful for creating tabs as in the tabs of your web browser, not \t characters. Let’s look at an example.

import teek

window = teek.Window("Notebook Example")
notebook = teek.Notebook(window)
notebook.pack(fill='both', expand=True)

for number in [1, 2, 3]:
    label = teek.Label(notebook, "Hello {}!".format(number))
    tab = teek.NotebookTab(label, text="Tab {}".format(number))
    notebook.append(tab)

window.geometry(300, 200)
window.on_delete_window.connect(teek.quit)
teek.run()

This program displays a notebook widget with 3 tabs. Let’s go trough some of the code.

label = teek.Label(notebook, "Hello {}!".format(number))

The label is created as a child widget of the notebook, because it will be added to the notebook eventually. However, we don’t use a geometry manager because the notebook itself handles showing the widget.

tab = teek.NotebookTab(label, text="Tab {}".format(number))

We need to create a NotebookTab object in order to add a tab to the notebook. The NotebookTab objects themselves are not widgets. A NotebookTab represents a widget and its tab options like text.

notebook.append(tab)

Lists also have an append method, and this is no coincidence. Notebook widgets behave like lists, and if you can do something to a list, you can probably do it to a notebook as well. However, there are a few things you can’t do to notebook widgets, but you can do to lists:

  • You can’t put any objects you want into a Notebook. All the objects must be NotebookTabs.
  • You can’t slice notebooks like notebook[1:]. However, you can get a list of all tabs in the notebook with list(notebook) and then slice that.
  • You can’t sort notebooks like notebook.sort(). However, you can do sorted(notebook) to get a sorted list of NotebookTabs, except that it doesn’t quite work because tab objects can’t be compared with each other. Something like sorted(notebook, key=(lambda tab: tab.config['text'])) might be useful though.
  • You can’t add the same NotebookTab to the notebook twice, and in fact, you can’t create two NotebookTabs that represent the same widget, so you can’t add the same widget to the notebook as two different tabs.

Note that instead of this…

label = teek.Label(notebook, "Hello {}!".format(number))
tab = teek.NotebookTab(label, text="Tab {}".format(number))
notebook.append(tab)

…you can also do this:

notebook.append(
    teek.NotebookTab(
        teek.Label(notebook, "Hello {}!".format(number)),
        text="Tab {}".format(number)
    )
)

I recommend using common sense here. The first alternative is actually only half as many lines of code as the second one, even though it uses more variables. Try to keep the code readable, as usual.

Here is some reference:

class teek.Notebook(parent, **kwargs)[source]

This is the notebook widget.

If you try to add a tab that is already in the notebook, that tab will be moved. For example:

>>> notebook = teek.Notebook(teek.Window())
>>> tab1 = teek.NotebookTab(teek.Label(notebook, text="1"), text="One")
>>> tab2 = teek.NotebookTab(teek.Label(notebook, text="2"), text="Two")
>>> notebook.extend([tab1, tab2])
>>> list(notebook)      # doctest: +NORMALIZE_WHITESPACE
[NotebookTab(<teek.Label widget: text='1'>, text='One'),
 NotebookTab(<teek.Label widget: text='2'>, text='Two')]
>>> notebook.append(notebook[0])
>>> list(notebook)      # doctest: +NORMALIZE_WHITESPACE
[NotebookTab(<teek.Label widget: text='2'>, text='Two'),
 NotebookTab(<teek.Label widget: text='1'>, text='One')]

For doing advanced magic, you can create a new class that inherits from Notebook. Here are some facts that can be useful when deciding which methods to override:

  • Override __delitem__() to customize removing tabs from the notebook. A deletion like del notebook[index] does notebook.__delitem__(index), which calls pathName forget documented in ttk_notebook(3tk). All other kinds of deletions call __delitem__ as well.
  • Override insert() if you want to customize adding new tabs to the notebook. The insert method is called every time when a new tab is added with any method. Make sure that your override is compatible with the insert() method of collections.abc.MutableSequence, and make sure that only the order of the tabs changes if the new tab is already in the notebook.
  • Bind to <<NotebookTabChanged>> if you want to customize what happens when a different tab is selected. That runs when the user changes a tab or the tab is changed with the selected_tab property. <<NotebookTabChanged>> is documented in the VIRTUAL EVENTS section of ttk_notebook(3tk).

As usual, use super() when overriding.

Manual page: ttk_notebook(3tk)

append_and_select(tab)[source]

A convenient way to add a tab to the notebook and select it.

notebook.append_and_select(tab) is same as:

notebook.append(tab)
notebook.selected_tab = tab
get_tab_by_widget(widget)[source]

Finds a NotebookTab object by the widget attribute.

If there is no tab with the given widget, a new tab is created.

>>> notebook = teek.Notebook(teek.Window())
>>> label = teek.Label(notebook, text='lol')
>>> tab = teek.NotebookTab(label)
>>> notebook.append(tab)
>>> tab
NotebookTab(<teek.Label widget: text='lol'>)
>>> notebook.get_tab_by_widget(label)
NotebookTab(<teek.Label widget: text='lol'>)
move(tab, new_index)[source]

Move a tab so that after calling this, self[new_index] is tab.

The new index may be negative. IndexError is raised if the index is not in the correct range.

selected_tab

This is the tab that the user is currently looking at.

This is None if there are no tabs in the notebook. You can set this to any other tab in the notebook to change the currently selected tab.

class teek.NotebookTab(widget, **kwargs)[source]

Represents a tab that is in a notebook, or is ready to be added to a notebook.

The widget must be a child widget of a Notebook widget. Each NotebookTab belongs to the widget’s parent notebook; for example, if you create a tab like this…

tab = teek.NotebookTab(teek.Label(asd_notebook, "hello"))

…then the tab cannot be added to any other notebook widget than asd_notebook, because asd_notebook is the parent widget of the label.

Most methods raise RuntimeError if the tab has not been added to the notebook yet. This includes doing pretty much anything with config.

For convenience, options can be passed when creating a NotebookTab, so that this…

notebook.append(teek.NotebookTab(some_widget, text="Tab Title"))

…does the same thing as this:

tab = teek.NotebookTab(some_widget, text="Tab Title")
notebook.append(tab)
tab.config['text'] = "Tab Title"

There are never multiple NotebookTab objects that represent the same tab.

config

Similar to the config attribute that widgets have. The available options are documented as TAB OPTIONS in ttk_notebook(3tk). Attempting to use this raises RuntimeError if the tab hasn’t been added to the notebook yet.

widget

This attribute and initialization argument is the widget in the tab. It should be a child widget of the notebook. Use tab.widget.parent to access the Notebook that the tab belongs to.

initial_options

A dict of keyword arguments passed to NotebookTab. When the tab is added to the notebook for the first time, config is updated from this dict.

hide()[source]

Call pathName hide documented in ttk_notebook(3tk).

Use unhide() to make the tab visible again. RuntimeError is raised if the tab has not been added to a notebook.

unhide()[source]

Undo a hide() call.