Skip to content
Advertisement

Accessing variables from other tab in notebook

Tab1 and Tab2 of the notebook

Hi all, I was unsuccessful with my last question in this group because my code was too long. I have now brought my code to a minimum and added a screenshot. I hope this time everything is clear and not confusing. My question is: how can I check the variable “val” in Tab1 whether it is smaller than 5. If not, the frame and button in Tab1 must be gray and disabled. The button must not do anything. The problem is that I have defined “val” as global, but it still brings the error message that “val” is unknown. Any idea why “val” is not known in Tab1?

# Filename: Tab1.py
from tkinter import *

def gen_t1(frame):
    global val
  
    f = LabelFrame(frame, text='f', bg='lightgreen')
    f.pack(expand=True, fill='both')

    b1 = Button(f, text='B1').pack()

##    if val < 5:
##        f_enabled = 'disabled'
##        f['bg'] = 'lightgray'
##    else:
##        f_enabled = 'normal'
##        f['bg'] = 'lightgreen'

# Filename: Tab2.py
from tkinter import *

def gen_t2(frame):
    def getValue(event):
        global val
        val = ent.get()
        print(val)

    lbl = Label(frame, text='Val').pack()

    ent = Entry(frame)
    ent.pack()
    ent.insert(0, '2')
  
    ent.bind('<Return>', getValue)

# Filename: TabTop
from tkinter import *
from tkinter import ttk

from Tab1 import gen_t1
from Tab2 import gen_t2

firstTime1 = 1
firstTime2 = 1
root = Tk()
root.title('Tab-Tester')
root.geometry('300x200')

nb = ttk.Notebook(root)
tab1 = Frame(nb)
tab2 = Frame(nb)
  
nb.add(tab1, text ='Tab 1')
nb.add(tab2, text ='Tab 2')
nb.pack(expand = 1, fill ="both")

def on_tab_change(event):
    global firstTime1, firstTime2
  
    tab = event.widget.tab('current','text')
    if tab == 'Tab 1':
        print('Tab 1')
        if firstTime1 == 1:
            gen_t1(tab1)
            firstTime1 = 0
    elif tab == 'Tab 2':
        print('Tab 2')
        if firstTime2 == 1:
            gen_t2(tab2)
            firstTime2 = 0
nb.bind('<<NotebookTabChanged>>', on_tab_change)

root.mainloop()

Advertisement

Answer

I think you should use the object-oriented way to build your GUI. From what I understood of your situation, here’s my suggested solution:

Tab1.py

import tkinter as tk
from tkinter import ttk

class Button_page(ttk.Frame):
    """This will contain what is going to be shown on the first tab."""

    def __init__(self, variable_to_check, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.variable_to_check = variable_to_check
        self.variable_to_check.trace('w', lambda *args: self.update_background())

        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)

        self.internal_style = ttk.Style()
        self.internal_style.configure('Tab1.TLabelframe', background='lightgreen')
        self.internal_style.configure('Tab1.TLabelframe.Label', background='lightgreen')

        self.f = ttk.LabelFrame(self, text='f', style='Tab1.TLabelframe')
        self.f.grid(column=0, row=0, sticky=(tk.N, tk.S, tk.E, tk.W))
        self.f.columnconfigure(0, weight=1)
        self.f.rowconfigure(0, weight=0)

        self.b1 = ttk.Button(self.f, text='B1')
        self.b1.grid(column=0, row=0, sticky=(tk.N,))

    def update_background(self):
        new_value_string = self.variable_to_check.get()
        try:
            new_value = int(new_value_string)
        except (ValueError):
            new_value = 0

        if new_value < 5:
            self.internal_style.configure('Tab1.TLabelframe', background='lightgray')
            self.internal_style.configure('Tab1.TLabelframe.Label', background='lightgray')
            self.b1.config(state=tk.DISABLED)
        else:
            self.internal_style.configure('Tab1.TLabelframe', background='lightgreen')
            self.internal_style.configure('Tab1.TLabelframe.Label', background='lightgreen')
            self.b1.config(state=tk.NORMAL)
           

Tab2.py

import tkinter as tk
from tkinter import ttk

class Entry_page(ttk.Frame):
    """This will contain what is going to be shown on the second tab."""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.entry_value = tk.StringVar()

        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=0)
        self.rowconfigure(1, weight=0)

        value_label = ttk.Label(self, text='Val')
        value_label.grid(column=0, row=0)

        value_entry = ttk.Entry(self, textvariable=self.entry_value)
        value_entry.grid(column=0, row=1)

TabTop.py

import tkinter as tk
from tkinter import ttk

import Tab1
import Tab2

root = tk.Tk()
root.title('Tab-Tester')
root.geometry('300x200')

root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)

nb = ttk.Notebook(root)
t2 = Tab2.Entry_page(nb)
t1 = Tab1.Button_page(variable_to_check=t2.entry_value, master=nb)
t2.entry_value.set(2)

nb.add(t1, text='Tab 1')
nb.add(t2, text='Tab 2')
nb.grid(column=0, row=0, sticky=(tk.N, tk.S, tk.E, tk.W))
nb.columnconfigure(0, weight=1)
nb.rowconfigure(0, weight=1)

root.mainloop()

To synchronize the information between the two tabs, you need a tkinter variable instance that you connect between the ttk.Entry and a callback function that will be triggered when the content of the ttk.Entry‘s is changed.

I know there’s not a lot of documentation on tkinter. I would recommend :


We could go even more object-oriented:

TabTop2.py

import tkinter as tk
from tkinter import ttk

import Tab1
import Tab2

class Tab_pages_application(tk.Tk):

    def __init__(self, title, size, value_page, action_page, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.title(title)
        self.geometry(size)

        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)

        nb = ttk.Notebook(self)
        t2 = value_page(nb)
        t1 = action_page(variable_to_check=t2.entry_value, master=nb)
        t2.entry_value.set(2)

        nb.add(t1, text='Tab 1')
        nb.add(t2, text='Tab 2')
        nb.grid(column=0, row=0, sticky=(tk.N, tk.S, tk.E, tk.W))
        nb.columnconfigure(0, weight=1)
        nb.rowconfigure(0, weight=1)

if __name__ == '__main__':
    root = Tab_pages_application('Tab-Tester', '300x200', Tab2.Entry_page, Tab1.Button_page)
    root.mainloop()

Is that what your tried to do?

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement