Home > Back-end >  tkinter call a root function from a toplevel window
tkinter call a root function from a toplevel window

Time:05-02

hello I would like to call a function in the root window from a Toplevel window. I want to create new tabs in the first window from a preference window (with parameters) But i recieve an error code :

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.3312.0_x64__qbz5n2kfra8p0\lib\tkinter\__init__.py", line 1892, in __call__
    return self.func(*args)
  File "C:\mircirc\gui_preferences.py", line 12, in add_tab
    master.new_tab()
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.3312.0_x64__qbz5n2kfra8p0\lib\tkinter\__init__.py", line 2354, in __getattr__
    return getattr(self.tk, attr)
AttributeError: '_tkinter.tkapp' object has no attribute 'new_tab'

What Have i forgotten or not understood ?

Here is my first root window : it's create some tabs and i want to create more tabs from a top level window with the root function new_tab()

from tkinter import ttk
from gui_preferences import *


class GUI_PRINCIPAL():
    def __init__(self):
        salons = ["#Radio-Evasion", "#un-autre-regard"]

        root = Tk()
        notebook = ttk.Notebook(root)
        ttk.Frame(notebook)
        root.title("Principale")

        def ouvre_gui_preferences():
            GUI_PREFERENCES(root)

        def do_something():
            print("Menu clicked")

        def create_menu_bar(self):
            menu_bar = Menu(self)

            menu_file = Menu(menu_bar, tearoff=0)
            menu_file.add_command(label="New", command=do_something)
            menu_file.add_command(label="Save", command=do_something)
            menu_file.add_separator()
            menu_file.add_command(label="Preferences", command=ouvre_gui_preferences)
            menu_file.add_separator()
            menu_file.add_command(label="Exit", command=self.quit)
            menu_bar.add_cascade(label="File", menu=menu_file)

            menu_outils = Menu(menu_bar, tearoff=0)
            menu_bar.add_cascade(label="Outils", menu=menu_outils)
            # menu_outils.add_command(label="Annonces", command=ouvre_annonces)
            menu_outils.add_command(label="!cmd", command=ouvre_gui_preferences)

            menu_help = Menu(menu_bar, tearoff=0)
            menu_help.add_command(label="About", command=do_something)
            menu_bar.add_cascade(label="Help", menu=menu_help)

            self.config(menu=menu_bar)

        def add_tab(tab_text):
            tab_name = Frame(notebook)
            notebook.add(tab_name, text="{}".format(tab_text))

        def new_tab():
            tab_name = Frame(notebook)
            notebook.add(tab_name, text="{}".format("tab_text"))

        # creation Menu
        create_menu_bar(root)
        # Création des Tabs salons
        for i, salon in enumerate(salons):
            add_tab(salons[i])
        notebook.pack(expand=True, fill="both")
        root.mainloop()


gui = GUI_PRINCIPAL()

Here is my TopLevel window

from tkinter import *
from tkinter.ttk import *


class GUI_PREFERENCES(Toplevel):
    def __init__(self, master=None, irc=None):
        super().__init__(master=master)
        self.title("Preferences")
        self.geometry(" 90 90")

        def add_tab():
            master.new_tab()

        self.btn_add = Button(self, text="Append tab", state='normal', command=add_tab)
        self.btn_add.grid(row=1, column=0, padx=(5, 0))v

CodePudding user response:

Issues

  • Currently, your new_tab() function is a local function known to only the members sitting inside the __init__ method of GUI_PRINCIPAL.
  • A function sitting in GUI_PRINCIPAL can't be accessed by the toplevel because you are passing the GUI_PRINCIPAL.root as master to the toplevel. And the tk.Tk object doesn't have a new_tab function.

Fixes

  • Move the functions out of __init__ method of GUI_PRINCIPAL
  • You can make the GUI_PRINCIPAL class inherit from tk.Tk and then it would be a lot easier to do or you can take the GUI_PRINCIPAL as an argument with the master argument in the toplevel class.

Following some naming conventions may make the code look cleaner, but thats left to you.

Complete Code

With all the fixes applied, your code should look like following

# try not to import globally
import tkinter as tk
from tkinter import ttk


class Preferences(tk.Toplevel):
    def __init__(self, master, *args, **kwargs):
        super().__init__(master, *args, **kwargs)
        self.master = master

        self.title("Preferences")
        self.geometry(" 90 90")

        def add_tab():
            master.new_tab()

        self.btn_add = tk.Button(self, text="Append tab", state='normal', command=add_tab)
        self.btn_add.grid(row=1, column=0, padx=(5, 0))


class Principal(tk.Tk):
    def __init__(self, master=None, *args, **kwargs):
        super().__init__(master, *args, **kwargs)
        self.title("Principale")

        salons = ["#Radio-Evasion", "#un-autre-regard"]
        self.notebook = ttk.Notebook(self)
        ttk.Frame(self.notebook)

        
        # creation Menu
        self.create_menu_bar()
        # Création des Tabs salons
        for i, salon in enumerate(salons):
            self.add_tab(salons[i])
        self.notebook.pack(expand=True, fill="both")

    def ouvre_gui_preferences(self):
        Preferences(self)

    def do_something(self):
        print("Menu clicked")

    def create_menu_bar(self):
        menu_bar = tk.Menu(self)

        menu_file = tk.Menu(menu_bar, tearoff=0)
        menu_file.add_command(label="New", command=self.do_something)
        menu_file.add_command(label="Save", command=self.do_something)
        menu_file.add_separator()
        menu_file.add_command(label="Preferences", command=self.ouvre_gui_preferences)
        menu_file.add_separator()
        menu_file.add_command(label="Exit", command=self.quit)
        menu_bar.add_cascade(label="File", menu=menu_file)

        menu_outils = tk.Menu(menu_bar, tearoff=0)
        menu_bar.add_cascade(label="Outils", menu=menu_outils)
        # menu_outils.add_command(label="Annonces", command=ouvre_annonces)
        menu_outils.add_command(label="!cmd", command=self.ouvre_gui_preferences)

        menu_help = tk.Menu(menu_bar, tearoff=0)
        menu_help.add_command(label="About", command=self.do_something)
        menu_bar.add_cascade(label="Help", menu=menu_help)

        self.config(menu=menu_bar)

    
    def add_tab(self, tab_text):
        tab_name = tk.Frame(self.notebook)
        self.notebook.add(tab_name, text="{}".format(tab_text))

    def new_tab(self):
        tab_name = tk.Frame(self.notebook)
        self.notebook.add(tab_name, text="{}".format("tab_text"))


root = Principal()
root.mainloop()
  • Related