How change tkinter Notebook tab and keep configuration?

Question:

I have a gui with two tabs and would like to switch back and forth between the tabs while keeping the content of the tabs. If I do this all in one function, then it works fine, but since I have more in the individual functions. I have outsourced them. Now I have bound the individual functions to the tabs. But here I have the problem that I overwrite the tabs with every change. But I would like to switch between the tabs without overwriting the entries. I understand why I overwrite the input. After all, I call the individual functions with rountine and overwrite them that way. Unfortunately I do not know how to do it better.


import tkinter as tk
from tkinter import ttk

class display():

    def __init__(self):
        self.root = tk.Tk()
        self.root.geometry('400x300')
        self.root.title('Notebook Demo')


    def gui(self):
        # create a notebook
        self.notebook = ttk.Notebook(self.root)
        self.notebook.place(rely=0.0, relheight=1, relwidth=1)

        # create frames
        self.frame1 = ttk.Frame(self.notebook, width=400, height=280)
        self.frame2 = ttk.Frame(self.notebook, width=400, height=280)

        self.frame1.place(rely=0.0, relheight=1, relwidth=1)
        self.frame2.place(rely=0.0, relheight=1, relwidth=1)

        # add frames to notebook
        self.notebook.add(self.frame1, text='General Information')
        self.notebook.add(self.frame2, text='Profile')
        self.notebook.bind("<<NotebookTabChanged>>", self.routine)
        self.gu1()


        self.root.update_idletasks()
        self.root.mainloop()

    def routine(self,event):
        if self.notebook.index("current") == 1:
            self.gu1()
        else:
            self.gu2()

    def gu1(self):
        button1 = tk.Button(self.frame1, text="test1", command=self.changeText)
        button1.grid(column=0, row=0)

        self.label1 = tk.Label(self.frame1, text="test1")
        self.label1.grid(column=1, row=0)

        self.root.mainloop()

    def gu2(self):
        button2 = tk.Button(self.frame2, text="test2", command=self.changeText2)
        button2.grid(column=0, row=0)

        self.label2 = tk.Label(self.frame2, text="test2")
        self.label2.grid(column=1, row=0)
        self.root.mainloop()

    def changeText(self):
        self.label1["text"] = "change1"

    def changeText2(self):
        self.label2["text"] = "change2"


if __name__ == "__main__":
    display().gui()

Asked By: lu3si

||

Answers:

All problem is that you use .gu1() and .gu2() in routine().

You should run .gu1() and .gu2() only once – at start in gui().

    def gui(self):
        # ... code ...

        self.notebook.bind("<<NotebookTabChanged>>", self.routine)
        
        self.gu1()   # create at start
        self.gu2()   # create at start

    def routine(self,event):
        if self.notebook.index("current") == 1:
            #self.gu1()  # DON'T DO THIS
            print('selected tab 1')
        else:
            #self.gu2()  # DON'T DO THIS
            print('selected tab 2')

Working code:

tkinter should use only one mainloop()

import tkinter as tk
from tkinter import ttk

class display():

    def __init__(self):
        self.root = tk.Tk()
        self.root.geometry('400x300')
        self.root.title('Notebook Demo')

    def gui(self):
        # create a notebook
        self.notebook = ttk.Notebook(self.root)
        self.notebook.place(rely=0.0, relheight=1, relwidth=1)

        # create frames
        self.frame1 = ttk.Frame(self.notebook, width=400, height=280)
        self.frame2 = ttk.Frame(self.notebook, width=400, height=280)

        self.frame1.place(rely=0.0, relheight=1, relwidth=1)
        self.frame2.place(rely=0.0, relheight=1, relwidth=1)

        # add frames to notebook
        self.notebook.add(self.frame1, text='General Information')
        self.notebook.add(self.frame2, text='Profile')
        self.notebook.bind("<<NotebookTabChanged>>", self.routine)
        self.gu1()
        self.gu2()

        self.root.update_idletasks()
        self.root.mainloop()

    def routine(self,event):
        if self.notebook.index("current") == 1:
            #self.gu1()  # DON'T DO THIS
            print('selected tab 1')
        else:
            #self.gu2()  # DON'T DO THIS
            print('selected tab 2')
            
    def gu1(self):
        button1 = tk.Button(self.frame1, text="test1", command=self.changeText)
        button1.grid(column=0, row=0)

        self.label1 = tk.Label(self.frame1, text="test1")
        self.label1.grid(column=1, row=0)

    def gu2(self):
        button2 = tk.Button(self.frame2, text="test2", command=self.changeText2)
        button2.grid(column=0, row=0)

        self.label2 = tk.Label(self.frame2, text="test2")
        self.label2.grid(column=1, row=0)

    def changeText(self):
        self.label1["text"] = "change1"

    def changeText2(self):
        self.label2["text"] = "change2"


if __name__ == "__main__":
    display().gui()

EDIT:

If you have to create some widgets in tabs with delays (ie. to wait for user’s values in other widgets) then you should use boolean variables (True/False) to run it only once in routine()

    def gui(self):
        # ... code ...

        self.gu1_created = False        
        self.gu2_created = False        

        self.notebook.bind("<<NotebookTabChanged>>", self.routine)


    def routine(self,event):
        if self.notebook.index("current") == 1:
            if not self.gu1_created:
                self.gu1()
                self.gu1_created = True
            print('selected tab 1')
        else:
            if not self.gu2_created:
                self.gu2()
                self.gu2_created = True
            print('selected tab 2')
Answered By: furas
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.