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?