I have a settings page with lots of checkbuttons on it so I am trying to reduce the code but I am struggling when it comes to getting the checkbutton value to work so far I have:-
def _create_checkbox(self, label, index, state=0):
x = label.replace(" ", "-").lower()
self.settings_list[x] = state
ttk.Label(self.settings_frame, text=label).grid(
row=index, column=0)
ttk.Checkbutton(
self.settings_frame, variable=self.settings_list[x]
).grid(row=index, column=1)
the idea was to put the checkbutton names in a dict and then update the dict with the value but it is not working as planned, with my code all checkbutton values update as if they were one.
example list:
self.settings_list = {"force-gamemode": "0", "allow-cheats": "1"}
Edit to show minimal working example, I did originally try to use variables (IntVar) but it failed (I cant remember why) but that's why I then switched to a dict:-
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("tkinter dynamic checkbox example")
self.geometry("700x450")
self.settings_list = {"force-gamemode": "0", "allow-cheats": "1"}
self.settings_frame = tk.Frame(self)
self.settings_frame.grid(row=0, column=0)
# create settings content
self._create_checkbox("Force Gamemode", 0, 0)
tk.Label(
self.settings_frame, text="Label to show content between checkboxes"
).grid(row=1, column=0)
self._create_checkbox("Allow Cheats", 2, 0)
tk.Button(
self.settings_frame,
text="Create Properties File",
command=self._create_properties,
).grid(row=3, column=0, sticky="ew")
def _create_checkbox(self, label, index, state=0):
x = label.replace(" ", "-").lower()
self.settings_list[x] = state
ttk.Label(self.settings_frame, text=label).grid(
row=index, column=0, padx=5, pady=5, sticky="w"
)
ttk.Checkbutton(self.settings_frame, variable=self.settings_list[x]).grid(
row=index, column=1, padx=5, pady=5, sticky="w"
)
def _create_properties(self):
print(self.settings_list["force-gamemode"])
print(self.settings_list["allow-cheats"])
if __name__ == "__main__":
app = App()
app.mainloop()
Since you passed an integer 0 as the textvariable option of those Checkbutton widgets, an implicit IntVar will be created with name "0" for them. Therefore they will be changed together because they share same tkinter variable.
You need to change
self.settings_list[x] = state
to
self.settings_list[x] = tk.IntVar(value=state)
inside _create_checkbox().
In addition to acw1668's answer, to check the value
def _create_properties(self):
print(self.settings_list["force-gamemode"].get())
print(self.settings_list["allow-cheats"].get())
so your code is ...
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("tkinter dynamic checkbox example")
self.geometry("700x450")
self.settings_list = {"force-gamemode": "0", "allow-cheats": "0"}
self.settings_frame = tk.Frame(self)
self.settings_frame.grid(row=0, column=0)
# create settings content
self._create_checkbox("Force Gamemode", 0, 0)
tk.Label(self.settings_frame, text="Label to show content between checkboxes"
).grid(row=1, column=0)
self._create_checkbox("Allow Cheats", 2, 0)
tk.Button(self.settings_frame, text="Create Properties File",
command=self._create_properties
).grid(row=3, column=0, sticky="ew")
def _create_checkbox(self, label, index, state=0):
x = label.replace(" ", "-").lower()
self.settings_list[x] = tk.IntVar(value=state)
ttk.Label(self.settings_frame, text=label
).grid(row=index, column=0, padx=5, pady=5, sticky="w")
ttk.Checkbutton(self.settings_frame, variable=self.settings_list[x]
).grid(row=index, column=1, padx=5, pady=5, sticky="w")
def _create_properties(self):
print(self.settings_list["force-gamemode"].get())
print(self.settings_list["allow-cheats"].get())
if __name__ == "__main__":
app = App()
app.mainloop()
Related
How do I pass data between parent and child windows and preserve data/unique IDs?
If I use the destroy() method for closing a child window, associated values are destroyed too, even when the dictionary that I send values to was initiated with the parent. Clicking on the Get child1config button after destroying the child window gives the error:
_tkinter.TclError: invalid command name ".!child1.!entry"
So, I don't destroy. Is it recommended to withdraw and deiconify many child windows?
How do I refer to the child window (and associated values) from parent window? Am I doing it correctly?
import tkinter as tk
class parent(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.dic={}
self.dic["var"]=['default']
self.title("Parent")
self.button1=tk.Button(self,text="open child1", command = self.open_child1, width=20)
self.button1.grid(row=0,column=0, padx=5, pady=5)
self.button2=tk.Button(self,text="Get child1 config", command = self.get_child1_value, width=20)
self.button2.grid(row=0,column=1, padx=5, pady=5)
self.label1 = tk.Label(self, text="", width=10)
self.label1.grid(row=0,column=2, sticky='ew')
self.child1_from_parent=child1(self)
self.child1_from_parent.withdraw()
def open_child1(self):
self.child1_from_parent.deiconify()
def get_child1_value(self):
self.label1.config(text=(self.dic["var"][0]+' \n'+self.child1_from_parent.child1_entry.get()))
class child1(tk.Toplevel):
def __init__(self,master):
tk.Toplevel.__init__(self, master)
self.frame = tk.Frame(self)
self.title("Child")
self.label1 = tk.Label(self, text="Config 1", width=10)
self.label1.grid(row=0,column=0)
self.child1_entry = tk.Entry(self, width=10)
self.child1_entry.grid(row=0, column=1, padx=5, pady=5)
self.child1_entry.insert ( tk.END, self.master.dic['var'][0])
self.child1_entry.bind('<Return>', self.update_value)
self.button4=tk.Button(self,text="Close", command = self.close_child1, width=20)
self.button4.grid(row=0,column=2, padx=5, pady=5)
self.button5=tk.Button(self,text="destroy", command = self.destroy_child1, width=20)
self.button5.grid(row=0,column=3, padx=5, pady=5)
def update_value(self, event):
self.master.dic["var"][0]=self.master.child1_from_parent.child1_entry.get()
def close_child1(self):
self.withdraw()
def destroy_child1(self):
self.destroy()
def main():
parent().mainloop()
if __name__ == '__main__':
main()
My program will grow, so I am looking for expandability. Classes 'seems' like a good idea. I have a parent tkinter window running with live data, and I will open/navigate to different child windows to perform different functions while the main window is running, accessible, and receiving data from child windows.
The code you have can be changed fairly easily to fix the problem. Tkinter supports something called "Variable Classes" — see The Variable Classes (BooleanVar, DoubleVar, IntVar, StringVar) — which are very handy for storing and passing around data within tkinter apps. In particular, Entry widgets support storing their contents in one (see Entry widget options) simply by passing one to it via the textvariable= keyword argument when its created. Once that's done, the widgets current (or last) value can be retrieved at any time whether the Entry still exists or not.
Below is a modified version of your code with the modifications needed to create and use one to pass information that's put into the widget in the child window back to its parent. I've indicated the most important changes with # ALL CAPS COMMENTS. Also note that I have also reformatted your code so it follows the PEP 8 - Style Guide for Python Code recommendations and is more readable. I strongly suggest you read and follow these guidelines.
import tkinter as tk
class Parent(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.dic = {}
self.dic['var'] = ['default']
self.dic['child1_value'] = tk.StringVar(value='') # ADDED.
self.title("Parent")
self.button1 = tk.Button(self, text="open Child1",
command=self.open_child1, width=20)
self.button1.grid(row=0, column=0, padx=5, pady=5)
self.button2 = tk.Button(self, text="Get Child1 config",
command=self.get_child1_value, width=20)
self.button2.grid(row=0, column=1, padx=5, pady=5)
self.label1 = tk.Label(self, text="", width=10)
self.label1.grid(row=0, column=2, sticky='ew')
self.Child1_from_parent = Child1(self)
self.Child1_from_parent.withdraw()
def open_child1(self):
self.Child1_from_parent.deiconify()
def get_child1_value(self):
self.label1.config(text=self.dic['var'][0] + '\n' +
self.dic['child1_value'].get()) # CHANGED.
class Child1(tk.Toplevel):
def __init__(self, master):
tk.Toplevel.__init__(self, master)
self.frame = tk.Frame(self)
self.title("Child")
self.label1 = tk.Label(self, text="Config 1", width=10)
self.label1.grid(row=0, column=0)
# ADDED `textvariable=` keyword argument.
self.child1_entry = tk.Entry(self, width=10,
textvariable=master.dic['child1_value'])
self.child1_entry.grid(row=0, column=1, padx=5, pady=5)
self.child1_entry.insert(tk.END, self.master.dic['var'][0])
self.child1_entry.bind('<Return>', self.update_value)
self.button4=tk.Button(self, text="Close", command=self.close_child1, width=20)
self.button4.grid(row=0, column=2, padx=5, pady=5)
self.button5=tk.Button(self, text="destroy", command=self.destroy_child1,
width=20)
self.button5.grid(row=0, column=3, padx=5, pady=5)
def update_value(self, event):
self.master.dic['var'][0] = self.master.Child1_from_parent.child1_entry.get()
def close_child1(self):
self.withdraw()
def destroy_child1(self):
self.destroy()
def main():
Parent().mainloop()
if __name__ == '__main__':
main()
If I understand your question correctly then this code may help.
It is a minimal demonstration of a one parent many children implementation.
All data and micro changes to each child are maintained after closing child.
Keyboard short-cuts give access to all children and parent
Parent is accessible while child is active.
Real exit is via gate keeper dialog from messagebox.
Creating children is easy and open ended.
import tkinter as tk
from tkinter.messagebox import askyesno
def flexx(m, r = 0, c = 0, rw = 1, cw = 1):
if r != None:
m.rowconfigure(r, weight = rw)
if c != None:
m.columnconfigure(c, weight = cw)
class child(tk.Toplevel):
def __init__(self, master, title, key):
super().__init__(master)
self.transient(master)
self.title(title)
flexx(self)
self.protocol('WM_DELETE_WINDOW', self.toggle)
self.bind('<Escape>', self.toggle)
self.bind(key, self.toggle)
def toggle(self, event = None):
'''toggle child on|off'''
if self.winfo_viewable():
self.withdraw()
else:
self.deiconify()
self.focus_force()
class parent(tk.Tk):
def __init__(self, title, icon = None):
super().__init__()
self.title(title)
flexx(self)
self.protocol('WM_DELETE_WINDOW', self.closer)
self.bind('<Escape>', self.closer)
if icon:
self.iconbitmap(default = icon)
self.withdraw()
def maker(self, title, key, geom):
anon = child(self, title, key)
# Connect parent and child
self.bind(key, anon.toggle)
anon.geometry(geom)
return anon
def closer(self, event = None):
if askyesno(
title = 'Confirm', message = 'Really',
detail = 'Close Program?', default = 'no'):
self.destroy()
if __name__ == '__main__':
the = parent('The Parent', icon = None) # icon = '.\\Icons\\Py-006.ico')
w,h,x,y = 500, 500, 100, 50
the.geometry(f'{w}x{h}+{x}+{y}')
the.boy = the.maker('harri', '<Control-h>', f'200x200+{x+w+5}+{y}')
the.girl = the.maker('suzie', '<Control-s>', f'200x200+{x+w+5}+{y+235}')
# make all other children
# inter-connect all children
the.girl.bind('<Control-h>', the.boy.toggle)
the.boy.bind('<Control-s>', the.girl.toggle)
the.deiconify()
the.mainloop( )
I need to take a value from user and then pass this value into function to get a string with this values. My code in first file looks like below (of course it is simplified version):
import tkinter as tk
from tkinter import ttk
import myfunction # this is my module that has another function
class Interface(ttk.Frame):
def __init__(self, container):
super().__init__(container)
self.user_price_minimum = tk.StringVar()
minimum_price = ttk.Label(self, text="Minimum price is: ")
minimum_price.grid(row=0, column=0, padx=5, pady=5)
minimum_price_entry = ttk.Entry(self, width=15, textvariable = self.user_price_minimum)
minimum_price_entry.grid(row=0, column=1)
minimum_price_entry.focus()
#############
button = ttk.Button(self, text="Use price")
button.grid(column=0, rows=2, columnspan=2, padx=5, pady=5)
root = tk.Tk()
root.geometry("450x250")
root.title("Looking for a flat")
root.columnconfigure(0, weight=1)
frame = Interface(root)
frame.pack()
root.mainloop()
My another python file that calls myfunction.py should be able to take this minimum_price from user and add this into string. Code looks like below:
def minimum_price(self):
price_min = self.user_price_minimum.get()
price_min = int(price_min)
print(f'Minimum price is: {price_min}')
So I am not sure how I could use minimum_price values from user into this function.
The simplest is to do this:
button = ttk.Button(self, text="Use price", command=lambda: myfunction.minimum_price(self))
However you could also define it as a method in the class itself:
class Interface(ttk.Frame):
def __init__(self, container):
super().__init__(container)
self.user_price_minimum = tk.StringVar()
minimum_price = ttk.Label(self, text="Minimum price is: ")
minimum_price.grid(row=0, column=0, padx=5, pady=5)
minimum_price_entry = ttk.Entry(self, width=15, textvariable = self.user_price_minimum)
minimum_price_entry.grid(row=0, column=1)
minimum_price_entry.focus()
#############
button = ttk.Button(self, text="Use price", command=self.print_price)
button.grid(column=0, rows=2, columnspan=2, padx=5, pady=5)
def print_price(self):
price = self.user_price_minimum.get()
print(f'Minimum price: {price}')
My personal preference (when using another file in such a case like this one (tho I would probably prefer to define this as above)) would be if:
# in the other file
def minimum_price(value):
print(f'Minimum price: {value}')
# inside the class
button = ttk.Button(self, text="Use price", command=lambda: myfunction.minimum_price(self.user_price_minimum.get()))
Also in this case you don't necessarily need the StringVar, you could also simply get the value by using:
# assignment
self.minimum_price_entry = ttk.Entry(self, width=15)
# get value (probably in some function call, basically the same way as with the `StringVar` except less code)
self.minimum_price_entry.get()
I have programmed a script which takes random four elements from a table and question to the user using tkinter, random and sqlite3. Currently, I can ask a question. Implement four choices with radiobuttons. I can also test if the answer is correct or not and show the result to the user via toplevel().
Problem is, how can I refresh the question after the continue button clicked?
My whole code is below. I have tried refreshing the random numbers and labels under continue_asking or another def called from continue_asking. But it doesn't work at all.
from tkinter import *
from sqlite3 import *
from random import *
class Question(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.grid()
self.prepare_question()
def prepare_question(self):
self.tumu = {0:['ask1','answer1'], # instead of SQL query
1:['ask2','answer2'],
2:['ask3','answer3'],
3:['ask4','answer4']}
self.create_widgets()
def create_widgets(self):
self.choiceFrame = Frame(self)
self.choiceFrame.grid(row=2, column=0)
self.choiceNum = IntVar()
for i in range(4):
Radiobutton(self.choiceFrame, text=self.tumu[i][1], variable=self.choiceNum, value=i) \
.grid(row=2, column=i, padx=5, pady=5)
self.q_num = randrange(4)
self.q_word = self.tumu[self.q_num][0]
lbl_question = Label(self, text="Which one is the meaning of the word: " + self.q_word, font="Courier 12")
lbl_question.grid(row=0, column=0, columnspan=4, padx=5, pady=5, sticky=W)
txt_question = Text(self, height=1, font="Courier 12", pady=2)
txt_question.tag_configure("myStyle", font="Courier 12 bold")
txt_question.insert("end", "Please choose the answer and ")
txt_question.insert("end", "click okay to see the results.", "myStyle")
txt_question.configure(state="disabled")
txt_question.grid(row=1, column=0, columnspan=4, padx=5, sticky=W)
btn_okay = Button(self, text="Okay", font="12", command=self.a_control)
btn_okay.grid(row=3, column=0, columnspan=2)
def a_control(self):
self.choosenWord = self.q_num
self.frm_answer = Toplevel()
self.frm_answer.title("Result")
self.selectedWord = self.choiceNum.get()
txt_result = Text(self.frm_answer, height=4, width = 40)
if self.choosenWord == self.selectedWord:
txt_result.insert("end", "Congrats! Your answer is correct.\n")
else:
txt_result.insert("end","Your answer is not correct.\n")
txt_result.insert("end", "Correct answer is " + self.tumu[self.q_num][1] + '\n')
txt_result.insert("end", "Please click Continue to continue.\n")
txt_result.insert("end", "Click cancel to quit.")
txt_result.grid(row=0, column=0, columnspan=2, padx = 5, pady=5)
txt_result.configure(state="disabled")
btn_continue = Button(self.frm_answer, text="Continue", command=lambda: self.continue_asking(self.frm_answer))
btn_continue.grid(row=1, column=0, padx=5, pady=5, sticky = W)
btn_quit = Button(self.frm_answer, text="Cancel", command=self.end_asking)
btn_quit.grid(row=1, column=1, padx=5, pady=5, sticky = W)
def continue_asking(self,frm_answer):
frm_answer.destroy()
def end_asking(self):
root.destroy()
root = Tk()
app = Question(root)
root.mainloop()
I have tried adding prepare_question to continue_asking. It keeps asking questions but widgets are not changing. They are just overlapping.
EDIT
So let's restart from scratch, i was totally wrong because no widget was removed and they stacked in the main Frame children list.
You still don't need to write so much code, mostly move some parts.
First, to be able to update the widgets and prepare the new question peacefully, move
self.create_widgets() in the constructor and put the random index self.q_num and self.q_word inside prepare_question, since it belongs to the logic of the question creation.
In create_widgets() you only need to keep some control on the label question, so we add self.lbl_question...
Finally, i suggest to create a new function update_widgets(), but you can put the logic inside continue_asking().
In this function, call prepare_question to update the next question (sql query and random stuff). Since we move the random index, everything is ready to update each widget:
text of the question label
text of radiobuttons. I'm not so proud of the loop to change those, but that'll do the trick. (we keep the values created for the indexes to match the new ones, i'm not very sure about this logic with SQL queries, i follow your first implementation with text=self.tumu[i][1])
If someone can tell how to get the radiobutton value more easily, i'm interested
Here is the whole code:
from tkinter import *
from sqlite3 import *
from random import *
class Question(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.grid()
self.prepare_question()
self.create_widgets()
def prepare_question(self):
self.tumu = {0:['ask1','answer1'], # instead of SQL query
1:['ask2','answer2'],
2:['ask3','answer3'],
3:['ask4','answer4']}
self.q_num = randrange(4)
self.q_word = self.tumu[self.q_num][0]
def create_widgets(self):
self.choiceFrame = Frame(self)
self.choiceFrame.grid(row=2, column=0)
self.choiceNum = IntVar()
for i in range(4):
Radiobutton(self.choiceFrame, text=self.tumu[i][1], variable=self.choiceNum, value=i) \
.grid(row=2, column=i, padx=5, pady=5)
self.lbl_question = Label(self, text="Which one is the meaning of the word: " + self.q_word, font="Courier 12")
self.lbl_question.grid(row=0, column=0, columnspan=4, padx=5, pady=5, sticky=W)
txt_question = Text(self, height=1, font="Courier 12", pady=2)
txt_question.tag_configure("myStyle", font="Courier 12 bold")
txt_question.insert("end", "Please choose the answer and ")
txt_question.insert("end", "click okay to see the results.", "myStyle")
txt_question.configure(state="disabled")
txt_question.grid(row=1, column=0, columnspan=4, padx=5, sticky=W)
btn_okay = Button(self, text="Okay", font="12", command=self.a_control)
btn_okay.grid(row=3, column=0, columnspan=2)
def a_control(self):
self.choosenWord = self.q_num
self.frm_answer = Toplevel()
self.frm_answer.title("Result")
self.selectedWord = self.choiceNum.get()
txt_result = Text(self.frm_answer, height=4, width = 40)
if self.choosenWord == self.selectedWord:
txt_result.insert("end", "Congrats! Your answer is correct.\n")
else:
txt_result.insert("end","Your answer is not correct.\n")
txt_result.insert("end", "Correct answer is " + self.tumu[self.q_num][1] + '\n')
txt_result.insert("end", "Please click Continue to continue.\n")
txt_result.insert("end", "Click cancel to quit.")
txt_result.grid(row=0, column=0, columnspan=2, padx = 5, pady=5)
txt_result.configure(state="disabled")
btn_continue = Button(self.frm_answer, text="Continue", command=self.continue_asking)
btn_continue.grid(row=1, column=0, padx=5, pady=5, sticky = W)
btn_quit = Button(self.frm_answer, text="Cancel", command=self.end_asking)
btn_quit.grid(row=1, column=1, padx=5, pady=5, sticky = W)
def continue_asking(self):
self.frm_answer.destroy()
self.update_widgets()
def update_widgets(self):
self.prepare_question()
# change question text
self.lbl_question.configure(text = "Which one is the meaning of the word: " + self.q_word)
# change Radiobutton
for child in self.choiceFrame.children.values():
index = child.config()['value'][4]
child.configure(text = self.tumu[index][1])
if index == 0: # reset the focus
child.select()
def end_asking(self):
root.destroy()
root = Tk()
app = Question(root)
root.mainloop()
First crap post: (the not to do part)
You don't need to change so much code to fix the present issue, have you already tried the following ?
def continue_asking(self,frm_answer):
frm_answer.destroy()
self.prepare_question()
I won't review the whole code, there is another place for that, but you can also avoid the lambda when you call continue_asking(), since you store the frame in self.frm_answer
btn_continue = Button(self.frm_answer, text="Continue", command=self.continue_asking)
# [...]
def continue_asking(self):
self.frm_answer.destroy()
self.prepare_question()
What I want to get: change of checkbox state changes the state of the Entry widget from 'disabled' into 'normal'. (checkbox off = Entry disabled, checkbox on = Entry normal).
My problem is that I don't know how to access and update the state of entry.
My code:
from tkinter import *
from tkinter import ttk
class App(Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master, padding='20')
self.grid()
self.create_checkbox()
self.create_entry()
def create_checkbox(self):
self.limit = BooleanVar()
Checkbutton(self,
text='Limit length',
variable= self.limit,
command= self.state_update,
).grid(row=1, column=1, sticky=W)
def create_entry(self):
self.entry_low = StringVar()
Entry(self,
width=6,
textvariable=self.entry_low,
state='disabled',
).grid(row=1, column=2, sticky=W)
def state_update(self):
self.entry_low.config(state="normal") #THIS OBVIOUSLY DOES NOT WORK
root = Tk()
root.title("Lottery")
app = App(root)
root.mainloop()
I'm beginner, so I'd be especially grateful for simple solutions.
Save a reference to the entry widget, then call the configure method. To make things easy, give your checkbutton the values for the states. That isn't strictly necessary, you can use a boolean and then translate that to the appropriate state.
def create_checkbox(self):
self.limit = StringVar(value="normal")
checkbutton = Checkbutton(..., onvalue="normal", offvalue="disabled", ...)
checkbutton.grid(...)
def create_entry(self):
self.entry_low = StringVar()
self.entry = Entry(self,
width=6,
textvariable=self.entry_low,
state='disabled',
)
self.entry.grid(row=1, column=2, sticky=W)
def state_update(self):
self.entry.config(state="normal") #THIS OBVIOUSLY DOES NOT WORK
Note: you need to call grid in a second step. grid(...) (as well as place) returns None. If you do x=Entry(...).grid(...), x will always be None.
I have been trying to desing a form in tkinter using python, but unfortunately I am stuck again, but now putting a form into the notebook I already have. I have run them separately and they work perfect, the problem starts when I try to put them together.
For example, if I write in "componentComb= ttk.Combobox(frameOne, width="19")" instead of frameOne I put firstStep which is what I want to do (merge them), I have an error like this:
componentComb= ttk.Combobox(firstStep, width="19")
NameError: name 'firstStep' is not defined
Which I don't understand, I have already defined, but probably wrong!!! Can you help me with this problem?
Below you have the code I have been "fighting" with, and I hope you can help me!
Thanks in advance
Here is my code:
#Starts
import Tkinter
from Tkinter import *
from ttk import *
import tkMessageBox
import ttk
# start of GUI code
root = Tk()
root.title("Model A")
root.minsize(1000, 150)
root.maxsize(1100, 200)
notebook = ttk.Notebook(root)
notebook.pack(fill='both', expand='yes')
notebook.pressed_index = None
# Child Frame
frameOne = Tkinter.Frame(notebook, bg='white')
frameOne.pack(fill='both', expand=True)
frameTwo = Tkinter.Frame(notebook, bg='white')
frameTwo.pack(fill='both', expand=True)
frameThree= Tkinter.Frame(notebook, bg='white')
frameThree.pack(fill='both', expand=True)
frameFour= Tkinter.Frame(notebook, bg='white')
frameFour.pack(fill='both', expand=True)
# Pages
notebook.add(frameOne, text='Standard')
notebook.add(frameTwo, text='TID')
notebook.add(frameThree, text='MEE')
notebook.add(frameFour, text='Final')
# Merging form and notebook
def defocus(event):
event.widget.master.focus_set()
if __name__ == '__main__':
firstStep = Tkinter.Label(notebook, text=" 1. Enter Main Details: ", font=("fixedsys", "16","bold italic"))
firstStep.grid(row=2, columnspan=7, sticky='W', \
padx=5, pady=5, ipadx=5, ipady=5)
#Main Selection
componentComb= ttk.Combobox(frameOne, width="19")
componentComb = Combobox(frameOne, state="readonly", values=("TGB", "RST", "CCPa"))
componentComb.grid(column=4, row=0, columnspan="5", sticky="nswe")
componentComb.set("Main Selection")
#Temperature Selection
tempComb = ttk.Combobox(frameOne, width="14")
tempComb = Combobox(frameOne, state="readonly", values=("-40", "-30", "-20","-10", "0", "10","20", "30"))
tempComb.grid(column=0, row=2, columnspan="2", sticky="w")
tempComb.set("Temperature Selection")
#Device Type Selection
DeviceTypeComb = ttk.Combobox(frameOne, width="14")
DeviceTypeComb = Combobox(frameOne, state="readonly", values=("QML", "Non-QML"))
DeviceTypeComb.grid(column=3, row=2, columnspan="2", sticky="w")
DeviceTypeComb.set("Device Type Selection")
#Junction Temperature Selection
JunctionTempComb = ttk.Combobox(frameOne, width="16")
JunctionTempComb = Combobox(frameOne, state="readonly", values=("-40", "-30", "-20","-10", "0", "10","20", "30"))
JunctionTempComb.grid(column=5, row=2, columnspan="2", sticky="w")
JunctionTempComb.set("Junction Temp Selection")
#Chip Area in Cm2 Selection
ChipAreaComb = ttk.Combobox(frameOne, width="12")
ChipAreaComb = Combobox(frameOne, state="readonly", values=("0.001","0.002","0.003","0.004","0.005","0.006"))
ChipAreaComb.grid(column=7, row=2, columnspan="2", sticky="e")
ChipAreaComb.set("Chip Area Selection")
#Time of Exposure
TimeOfExpoComb = ttk.Combobox(frameOne, width="12")
TimeOfExpoComb = Combobox(frameOne, state="readonly", values=("1", "2", "3","4", "5"))
TimeOfExpoComb.grid(column=9, row=2, columnspan="2", sticky="w")
TimeOfExpoComb.set("Time of Exposure")
root.mainloop()
firstStep is a local variable in the defocus function, and you are trying to access it in a global scope.
You have to define it outside of the function so that it has a meaning in the global scope. But note that because you are assigning it within the function, you need to use the global keyword so that it doesn't think you're introducing a new local variable with the same name.
This should work:
firstStep = None #define the variable globally
def defocus(event):
event.widget.master.focus_set()
if __name__ == '__main__':
global firstStep # we want to reassign the global version of this variable
firstStep = Tkinter.Label(notebook, text=" 1. Enter Main Details: ", font=("fixedsys", "16","bold italic"))
firstStep.grid(row=2, columnspan=7, sticky='W', \
padx=5, pady=5, ipadx=5, ipady=5)
componentComb= ttk.Combobox(firstStep, width="19")