Search code examples
pythonclasstkintermethods

Python tkinter notebook as a method in a class


This is a problem with creating a tkinter notebook in a method in a class.

This question is solved by removing master, which is not my problem: Python Tkinter - How add a notebook class into a tk.toplevel?.

This question is about adding images, and it doesn't have the same structure (from which I might have been able to infer the solution): Python Tkinter Notebook widget.

When I create the notebook from __init__, the notebook opens just fine.

import tkinter as tk
from tkinter import ttk

class Stakeholders(tk.Frame):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
    
        notebook = ttk.Notebook(self.master)
        notebook.pack(pady=10, expand=True)

        # create frames
        frame1 = ttk.Frame(notebook, width=400, height=280)
        frame2 = ttk.Frame(notebook, width=400, height=280)
        
        frame1.pack(fill='both', expand=True)
        frame2.pack(fill='both', expand=True)
        
        # add frames to notebook
        notebook.add(frame1, text='Tab 1')
        notebook.add(frame2, text='Tab 2')

def create_window():
    root = tk.Tk()
    root.geometry('400x300')
    root.title('Stakeholders')
    
    Stakeholders(root)
    root.mainloop()
    
if __name__ == "__main__":
    create_window()

When I put the notebook in a method of the class, the window opens but there is no notebook, no tabs.

import tkinter as tk
from tkinter import ttk

class Stakeholders(tk.Frame):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.make_notebook()
        
    def make_notebook(self):
        self.notebook = ttk.Notebook(self)
        self.notebook.pack(pady=10, expand=True)
        
        frame1 = ttk.Frame(self.notebook, width=300, height=300)
        frame2 = ttk.Frame(self.notebook, width=300, height=300)
        
        frame1.pack(fill='both', expand=True)
        frame2.pack(fill='both', expand=True)

        self.notebook.add(frame1, text='Owner')
        self.notebook.add(frame2, text='Architect')

def create_window():
    root = tk.Tk()
    root.geometry('400x300')
    root.title('Stakeholders')
    
    Stakeholders(root)
    root.mainloop()
    
if __name__ == "__main__":
    create_window()

Solution

  • You were very close, but need a few minor changes

    import tkinter as tk
    from tkinter import ttk
    
    
    class Stakeholders(tk.Frame):
        def __init__(self, *args, **kwargs) -> None:
            super().__init__(*args, **kwargs)
    
            notebook = ttk.Notebook(self)  # you want 'self' here, not self.master
            notebook.pack(pady=10, expand=True)
    
            # create frames
            frame1 = ttk.Frame(notebook, width=400, height=280)
            frame2 = ttk.Frame(notebook, width=400, height=280)
    
            frame1.pack(fill='both', expand=True)
            frame2.pack(fill='both', expand=True)
    
            # add frames to notebook
            notebook.add(frame1, text='Tab 1')
            notebook.add(frame2, text='Tab 2')
    
    
    def create_window() -> None:
        root = tk.Tk()
        root.geometry('400x300')
        root.title('Stakeholders')
        
        # instantiate your Stakeholders class
        stakeholders = Stakeholders(root)
        # add it to the UI via 'pack' or another layout manager (I tend to prefer pack)
        stakeholders.pack(expand=True, fill='both')
         
        root.mainloop()
    
    
    if __name__ == "__main__":
        create_window()
    
    1. You generally want your widgets to be children of the class they're in (i.e. master=self) rather than children of that class's parent (i.e. master=self.master)

    2. Calling a layout manager (e.g. pack, grid, or place) on your Stakeholders instance was the real missing piece - this is what adds it to the UI

      2a. Note that you could also use Stakeholders(root).pack(...). But it's a good idea to get in the habit of instantiating your widgets separately from layout management, because pack, grid, and place all return None. This means that when you do something like stakeholders = Stakeholders(root).pack(), stakeholders evaluates to None (and not your widget!) which can cause headaches down the line if you're not careful