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