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 :
- https://tkdocs.com/index.html
- Another site that used to have some more information but the site is not accessible at to moment (https://effbot.org/tkinterbook/) so you would have to go the Internet Archive Wayback Machine copy from November 2020 so see its information.
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?