I am creating a tkinter application where trying to get value from multiple checkboxes from different frames.When i am clicking the checkbox in one frame it is also checked in the other frame. I want to know how to access the checkbox value from different frames.
when trying to checking the checkbox (Tb1 in frame1) it is also checking in (NLTb1 in NLframe). I would like know how to access these two check box values separately.
from tkinter import *
def create_widgets_in_first_frame():
task_type=Button(main_frame,text='Task Type',command=call_second_frame_on_top).grid(row=6,column=0,sticky=W)
Network_Location=Button(main_frame,text='Network Location',command=call_third_frame_on_top).grid(row=7,column=0,sticky=W)
def create_widgets_in_second_frame():
T1=Label(frame1,text="Verify and ensure there is no duplicate entries present in task type",bg='Light blue')
T1.grid(row=3,columnspan=2,sticky=W)
#creating checkbutton
Tb1=Checkbutton(frame1,text='Pass',font=('Times New Roman',14),bg='Green')
Tb1.grid(row=3,column=4,padx=6)
#creating checkbuttonx
r2=Checkbutton(frame1,text='Fail',font=('Times New Roman',14),bg='red')
r2.grid(row=3,column=5,padx=6)
#creating Run button
b1=Button(frame1,text='Run').grid(row=3,column=6,padx=6)
button=Button(frame1,text='Go to Main page',command=call_first_frame_on_top)
button.grid(row=20,column=0,padx=6,sticky=W)
def create_widgets_in_third_frame():
NL1=Label(NLframe,text="Verify the migrated Network location in NGMSS and ensure all the mandatory information's are migrated along with it",bg='Light blue')
NL1.grid(row=3,columnspan=2,sticky=W)
#creating checkbutton
NLTb1=Checkbutton(NLframe,text='Pass',font=('Times New Roman',14),bg='Green')
NLTb1.grid(row=3,column=4,padx=6)
#creating checkbuttonx
nbr2=Checkbutton(NLframe,text='Fail',font=('Times New Roman',14),bg='red')
nbr2.grid(row=3,column=5,padx=6)
#creating Run button
nlb1=Button(NLframe,text='Run').grid(row=3,column=8)
button=Button(NLframe,text='Go to Main page',command= call_first_frame_on_top)
button.grid(row=20,column=0,padx=6,sticky=W)
def call_first_frame_on_top():
frame1.grid_forget()
NLframe.grid_forget()
main_frame.grid(row=0,column=0,sticky=W+E+N+S)
def call_second_frame_on_top():
NLframe.grid_forget()
main_frame.grid_forget()
frame1.grid(row=0,column=0,sticky=W+N+E+S)
def call_third_frame_on_top():
NLframe.grid(row=0,column=0,sticky=W+N+E+S)
frame1.grid_forget()
main_frame.grid_forget()
def quit_program():
root_window.destroy()
def raise_frame():
main_frame.tkraise()
root= Tk()
main_frame=Frame(root,height=30,width=500,borderwidth=10,bg='Powder Blue',highlightthickness=10,highlightcolor="red")
main_frame.grid(row=0,column=0,sticky=W+E+N+S)
frame1=Frame(root,height=30,width=500,borderwidth=10,bg='Powder Blue',highlightthickness=10,highlightcolor="red")
frame1.grid(row=0,column=0,sticky=W+N+E+S)
NLframe=Frame(root,height=30,width=500,borderwidth=10,bg='Powder Blue',highlightthickness=5,highlightcolor="red")
NLframe.grid(row=1,column=0,sticky=W+N+E+S)
create_widgets_in_third_frame()
create_widgets_in_second_frame()
create_widgets_in_first_frame()
frame1.grid_forget()
NLframe.grid_forget()
raise_frame()
root.mainloop()
`
Firstly, in your quit_program function, you call for root_window to be destroyed. You never defined this prior. My guess is you mean root.destroy()?
Secondly, I would say you might want to consider using radio buttons instead of checkboxes. Radio buttons will exclusively allow one option to be checked. This would prevent you from checking both the Pass and the Fail box on the same page.
As far as question is concerned, the reason your checkboxes are staying checked in the other frame because you are only forgetting the grid and not destroying the widgets. The grid is just what is organizing the widgets, not the actual widgets themselves. Therefore when you forget the grid and move to a new frame, the widget in that grid spot retains its state. Thats not to say destroying the widgets is the solution however. To fix your problem just make sure that you are storing the state of the button in a variable. I've tweaked your code a little bit and got it working.
from tkinter import *
def create_widgets_in_first_frame():
task_type = Button(main_frame, text='Task Type', command=call_second_frame_on_top).grid(row=6, column=0, sticky=W)
Network_Location = Button(main_frame, text='Network Location', command=call_third_frame_on_top).grid(row=7,
column=0,
sticky=W)
def create_widgets_in_second_frame():
t_var1 = BooleanVar()
t_var2 = BooleanVar()
T1 = Label(frame1, text="Verify and ensure there is no duplicate entries present in task type", bg='Light blue')
T1.grid(row=3, columnspan=2, sticky=W)
# creating checkbutton
Tb1 = Checkbutton(frame1, text='Pass', font=('Times New Roman', 14), bg='Green', variable=t_var1)
Tb1.grid(row=3, column=4, padx=6)
# creating checkbuttonx
r2 = Checkbutton(frame1, text='Fail', font=('Times New Roman', 14), bg='red', variable=t_var2)
r2.grid(row=3, column=5, padx=6)
# creating Run button
b1 = Button(frame1, text='Run').grid(row=3, column=6, padx=6)
button = Button(frame1, text='Go to Main page', command=call_first_frame_on_top)
button.grid(row=20, column=0, padx=6, sticky=W)
def create_widgets_in_third_frame():
nl_var1 = BooleanVar()
nl_var2 = BooleanVar()
NL1 = Label(NLframe,
text="Verify the migrated Network location in NGMSS and ensure all the mandatory information's are migrated along with it",
bg='Light blue')
NL1.grid(row=3, columnspan=2, sticky=W)
# creating checkbutton
NLTb1 = Checkbutton(NLframe, text='Pass', font=('Times New Roman', 14), bg='Green', variable=nl_var1)
NLTb1.grid(row=3, column=4, padx=6)
# creating checkbuttonx
nbr2 = Checkbutton(NLframe, text='Fail', font=('Times New Roman', 14), bg='red', variable=nl_var2)
nbr2.grid(row=3, column=5, padx=6)
# creating Run button
nlb1 = Button(NLframe, text='Run').grid(row=3, column=8)
button = Button(NLframe, text='Go to Main page', command=call_first_frame_on_top)
button.grid(row=20, column=0, padx=6, sticky=W)
def call_first_frame_on_top():
frame1.grid_forget()
NLframe.grid_forget()
main_frame.grid(row=0, column=0, sticky=W + E + N + S)
def call_second_frame_on_top():
NLframe.grid_forget()
main_frame.grid_forget()
frame1.grid(row=0, column=0, sticky=W + N + E + S)
def call_third_frame_on_top():
frame1.grid_forget()
main_frame.grid_forget()
NLframe.grid(row=0, column=0, sticky=W + N + E + S)
def quit_program():
root.destroy()
def raise_frame():
main_frame.tkraise()
root = Tk()
main_frame = Frame(root, height=30, width=500, borderwidth=10, bg='Powder Blue', highlightthickness=10,
highlightcolor="red")
main_frame.grid(row=0, column=0, sticky=W + E + N + S)
frame1 = Frame(root, height=30, width=500, borderwidth=10, bg='Powder Blue', highlightthickness=10,
highlightcolor="red")
frame1.grid(row=0, column=0, sticky=W + N + E + S)
NLframe = Frame(root, height=30, width=500, borderwidth=10, bg='Powder Blue', highlightthickness=5,
highlightcolor="red")
NLframe.grid(row=1, column=0, sticky=W + N + E + S)
create_widgets_in_third_frame()
create_widgets_in_second_frame()
create_widgets_in_first_frame()
frame1.grid_forget()
NLframe.grid_forget()
raise_frame()
root.mainloop()
Side note: In the future please take steps to make sure your code is readable and that you use proper naming conventions. You can find the PEP 8 Style Guide here.
Related
This question already has an answer here:
Tkinter assign button command in a for loop with lambda [duplicate]
(1 answer)
Closed last year.
I want to create a PanedWindow with variable number of panes which every one of these panes includes a label and a button. Pressing a button in a pane should write a messege to the corresponding label in that pane.
I tried this code:
from tkinter import *
from tkinter import ttk
n = 5
root = Tk()
root.geometry('250x500+100+100')
p = ttk.Panedwindow(root, orient=VERTICAL)
p.grid(column=0, row=0, sticky=(N, S, W, E))
for i in range(n):
pane = ttk.Labelframe(p, width=25, borderwidth=0)
p.add(pane)
def writeToLabel():
paneLabel.config(text='This is Pane number %d' %(i+1))
paneLabel = ttk.Label(pane, width=20, relief='solid')
paneButton = ttk.Button(pane, text='Press', command=writeToLabel)
paneButton.grid(column=0, row=0, padx=5)
paneLabel.grid(column=1, row=0, padx=5)
root.rowconfigure(0, weight=1)
root.mainloop()
But no matter which button is pressed the label in the last row is set with the message.
I would be grateful if somebody could help me to fix the problem.
I think this is the sort of thing you are looking for:
from tkinter import *
from tkinter import ttk
n = 5
root = Tk()
root.geometry('250x500+100+100')
p = ttk.Panedwindow(root, orient=VERTICAL)
p.grid(column=0, row=0, sticky=(N, S, W, E))
def writeToLabel(pl, i):
pl.config(text='This is Pane number %d' %(i+1))
for i in range(n):
pane = ttk.Labelframe(p, width=25, borderwidth=0)
p.add(pane)
paneLabel = ttk.Label(pane, width=20, relief='solid')
paneButton = ttk.Button(pane, text='Press', command=lambda pl=paneLabel, i=i: writeToLabel(pl, i))
paneButton.grid(column=0, row=0, padx=5)
paneLabel.grid(column=1, row=0, padx=5)
root.rowconfigure(0, weight=1)
root.mainloop()
Your current method does not work as the definition of writeToLabel will use the last value of paneLabel and i. You instead need to pass a reference to the label and the value of i using a lambda function. The pl=paneLabel and i=i parts of the lambda function are explained here.
I'm in the very early stages of making a GUI. Right now I have the log in view(LogInWind class) and the sign up view (SignUpWind class). Everything was fine when I only had one view but now I have a circular dependency with these two objects. This happens with the buttons' command since in the log in view there is a button that takes you to the sign up view and vise versa. I think I could just make a pop up window for the sign up view. Yet I think the way I'm switching windows is a bad practice an may bring bigger issues later on.
I'm project structure is the following.
the services package will do the connection between the gui and the database. At the moment it does nothing.
I'm happy to get feedback for everything. If further explanation is needed I'm happy to do so.
root.py
import tkinter as tk
from .log_in_window import LogInWind as LIWind
from .sign_up_window import SignUpWind as SuWind
from services.messenger import Messenger
class Root(tk.Tk):
def __init__(self, *args,**kwargs):
super().__init__(*args,**kwargs)
# General variables.
self.frames = {}
self.width_window
self.height_window
self.container = tk.Frame(self,relief="groove")
# General app configurations.
self.title("SECOM")
self.iconbitmap("C:/Users/joshu/Documents/VSC/python/secom/icons/icon.ico")
self.configure(bg="#E0E0E0")
# Container setup.
self.container.pack(side="top", fill="both", expand=True)
self.container.grid_rowconfigure(0, weight=1)
self.container.grid_columnconfigure(0, weight=1)
def createFrame(self, page_name):
"""
INPUT: view object.
OUTPUT: None
Description: creates frame for the view `page_name`.
"""
# Setup `newFrame.`
newFrame = page_name(parent=self.container, controller=self)
newFrame.configure(bg="#E0E0E0")
newFrame.grid(row=0, column=0, sticky=tk.NSEW)
# Add `newFrame` to catalog of frames.
self.__frames[page_name] = newFrame
def showFrame(self, page_name):
"""
INPUT: view object.
OUTPUT: None.
Calls the view `page_name` up front for display.
"""
try:
# Bings requested view to the front.
self.frames[page_name].tkraise()
except KeyError:
# Creates view and displays it.
self.createFrame(page_name)
self.frames[page_name].tkraise()
def setLocation(self):
"""
INPUT: None
OUTPUT: None
Description: Sets window in the middle of the screen.
"""
self.widthWindow = 400
self.heightWindow = 225
widthScreen = self.winfo_screenwidth()
hightScreen = self.winfo_screenheight()
x = (widthScreen / 2) - (self.widthWindow / 2)
y = (hightScreen / 2) - (self.heightWindow / 2)
self.geometry("%dx%d+%d+%d" % (self.widthWindow, self.heightWindow, x, y))
log_in_window.py
import tkinter as tk
import tkinter.font as tkf
from .sign_up_window import SignUpWind as SUWind # <-- circular dependency
class LogInWind(tk.Frame):
def __init__(self, parent, controller):
super().__init__(parent, controller)
# Creation of labels.
self.titleLbl = tk.Label(self,
text="Iniciar Secion",
font=tkf.Font(family="Helvetica", size=15, weight="bold"),
bg="#E0E0E0")
self.userLbl = tk.Label(self,
text="Usuario:",
font=tkf.Font(family="Helvetica", size=10, weight="bold"),
bg="#E0E0E0")
self.pswdLbl = tk.Label(self,
text="Contraseña:",
font=tkf.Font(family="Helvetica", size=10, weight="bold"),
bg="#E0E0E0")
# Creation of entries.
self.userEty = tk.Entry(self)
self.pswdEty = tk.Entry(self, show="*")
# Creation of buttons.
self.logInBtn = tk.Button(self,
width=15,
text="Iniciar Sesion",
font=tkf.Font(family="Helvetica", size=10, weight="bold"),
bg="#0080FF",
################################### ADD COMMAND
fg="#fff")
self.signUpBtn = tk.Button(self,
width=15,
text="Crear cuenta",
font=tkf.Font(family="Helvetica", size=10, weight="bold"),
bg="#0080FF",
command=lambda: controller.showFrame(SUWind), # <---- use object HERE.
fg="#fff")
# Places labels.
self.titleLbl.grid(row=0,
column=0,
padx=400 / 2 - 60,
pady=10,sticky=tk.SW)
self.userLbl.grid(row=1,
column=0,
padx=parent.width_window / 2 - 60,
sticky=tk.SW)
self.pswdLbl.grid(row=3,
column=0,
padx=parent.width_window / 2 - 60,
sticky=tk.W)
# Places entries (string inputs).
self.userEty.grid(row=2,
column=0,
padx=parent.width_window / 2 - 60,
pady=5)
self.pswdEty.grid(row=4,
column=0,
padx=parent.width_window / 2 - 60,
pady=5)
# # Places buttons
self.logInBtn.grid(row=5,column=0, sticky=tk.N)
self.signUpBtn.grid(row=6, column=0, sticky=tk.S, pady=10)
sing_up_window.py
import tkinter as tk
import tkinter.font as tkf
from .log_in_window import LogInWind as LIWind # <-- circular dependency
class SignUpWind(tk.Frame):
def __init__(self, parent, controller):
super().__init__(parent, controller)
# Setup imge for back button.
self.img = tk.PhotoImage(file="C:/Users/joshu/Documents/VSC/python/secom/icons/return.png")
self.img = self.img.subsample(4,4)
# Create label.
self.titleLbl = tk.Label(self,
text="Crear cuenta nueva",
font=tkf.Font(family="Helvetica", size=15, weight="bold"),
bg="#E0E0E0")
self.userLbl = tk.Label(self,
text="Usuario:",
font=tkf.Font(family="Helvetica", size=10, weight="bold"),
bg="#E0E0E0")
self.pswdLbl = tk.Label(self,
text="Contraseña:",
font=tkf.Font(family="Helvetica", size=10, weight="bold"),
bg="#E0E0E0")
self.pswdConfirmLbl = tk.Label(self,
text="Cormirma Contraseña:",
font=tkf.Font(family="Helvetica", size=10, weight="bold"),
bg="#E0E0E0")
# Creation of entries.
self.userEty = tk.Entry(self)
self.pswdEty = tk.Entry(self, show="*")
self.pswdConfirmEty = tk.Entry(self, show="*")
# Creation of button.
self.backBtn = tk.Button(self,
image=self.img,
command=lambda: controller.showFrame(LIWind)) <----- use object HERE.
self.CreateBtn = tk.Button(self,
width=8,
text="Crear",
font=tkf.Font(family="Helvetica", size=10, weight="bold"),
bg="#0080FF",
############################ ADD COMAND
fg="#fff")
# Places labels.
self.titleLbl.grid(row=0, column=0, padx=400 / 2 - 90, sticky=tk.SW)
self.userLbl.grid(row=1, column=0, padx=parent.width_window / 2 - 60, sticky=tk.W)
self.pswdLbl.grid(row=3, column=0, padx=parent.width_window / 2 - 60, sticky=tk.W)
self.pswdConfirmLbl.grid(row=5, column=0, padx=parent.width_window / 2 - 60, sticky=tk.W)
# Places entries (string inputs).
self.userEty.grid(row=2, column=0, padx=parent.width_window / 2 - 60, pady=5, sticky=tk.W)
self.pswdEty.grid(row=4, column=0, padx=parent.width_window / 2 - 60, pady=5, sticky=tk.W)
self.pswdConfirmEty.grid(row=6, column=0, padx=parent.width_window / 2 - 60, pady=5, sticky=tk.W)
# Places buttons
self.backBtn.grid(row=0, column=0,sticky=tk.W)
self.CreateBtn.grid(row=7, column=0, padx=100,sticky=tk.N)
main.py
from views.root import Root
from views.log_in_window import LogInWind as LIWind
if __name__ == '__main__':
root = Root()
root.showFrame(LIWind)
root.mainloop()
If you design your code so that you pass in the page name as a string rather than as a class then you won't have this problem.
For example, in root.py you can start with something like this:
pages = {
"log in": LIWind,
"sign up": SuWind,
}
Next, in createFrame you would do something like this:
def createFrame(self, page_name):
...
cls = pages[page_name]
newFrame = cls(parent=self.container, controller=self)
...
self.__frames[page_name] = newFrame
Then, anywhere you need the window you can pass in the page name, such as:
self.backBtn = tk.Button(..., command=lambda: controller.showFrame("log in"))
Recently, I tried to make a full application window with a side panel menu with separate frames running some functions and submitting forms in the canvas frame.
But I found that every time I click on any entry in listbox it runs the function or method without clearing the existing one .
I tried destroy() and forget() didn't work for me (maybe I didn't know exactly how to use it?!, and the destroy() function prevent using the function again till I close the whole application and run it again!) this is a photo of my problem
this is my code :
import tkinter as tk
from tkinter import ttk
class MainWindow() :
def __init__(self,root):
# menu left
self.menu_upper_frame = tk.Frame(root, bg="#dfdfdf")
self.menu_title_label = tk.Label(self.menu_upper_frame, text="menu title", bg="#dfdfdf")
self.menu_title_label.pack()
self.menu_left_container = tk.Frame(root, width=150, bg="#ababab")
self.menu_left_upper = tk.Frame(self.menu_left_container, width=150, height=150, bg="red")
self.menu_left_upper.pack(side="top", fill="both", expand=True)
# create a listbox of items
self.Lb1 = tk.Listbox(self.menu_left_upper,bg ="red", borderwidth=0, highlightthickness=0 )
self.Lb1.insert(1, "Python")
self.Lb1.insert(2, "Perl")
self.Lb1.insert(3, "C")
self.Lb1.insert(4, "PHP")
self.Lb1.insert(5, "JSP")
self.Lb1.insert(6, "Ruby")
self.Lb1.bind("<<ListboxSelect>>", self.OnClick ) #return selected item
self.Lb1.pack(fill="both", expand=True, pady=50 )
# right area
self.inner_title_frame = tk.Frame(root, bg="#dfdfdf")
self.inner_title_label = tk.Label(self.inner_title_frame, text="inner title", bg="#dfdfdf")
self.inner_title_label.pack()
self.canvas_area = tk.Canvas(root, width=500, height=400, background="#ffffff")
self.canvas_area.grid(row=1, column=1)
# status bar
self.status_frame = tk.Frame(root)
self.status = tk.Label(self.status_frame, text="this is the status bar")
self.status.pack(fill="both", expand=True)
self.menu_upper_frame.grid(row=0, column=0, rowspan=2, sticky="nsew")
self.menu_left_container.grid(row=1, column=0, rowspan=2, sticky="nsew")
self.inner_title_frame.grid(row=0, column=1, sticky="ew")
self.canvas_area.grid(row=1, column=1, sticky="nsew")
self.status_frame.grid(row=2, column=0, columnspan=2, sticky="ew")
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(1, weight=1)
def OnClick(self,event):
widget = event.widget
selection = widget.curselection()
value = widget.get(selection)
if value == 'Python':
self.tabtop()
def tabtop(self):
self.tabControl = ttk.Notebook(self.canvas_area, width=400) # Create Tab Control
self.tab1 = ttk.Frame(self.tabControl) # Create a tab
self.tab2 = ttk.Frame(self.tabControl)
self.tab3 = ttk.Frame(self.tabControl)
self.tab4 = ttk.Frame(self.tabControl)
self.tab5 = ttk.Frame(self.tabControl)
self.tabControl.add(self.tab1, text='Login data' ) # Add the tab
self.tabControl.add(self.tab2, text='Permission')
self.tabControl.add(self.tab3, text='Roles')
self.tabControl.add(self.tab4, text='Personal data')
self.tabControl.add(self.tab5, text='Business data')
self.tabControl.pack(expand=1, fill="both") # Pack to make visible
self.l2 = tk.Label(self.tab2, text="label 2").pack()
self.l3 = tk.Label(self.tab3, text="label 3").pack()
root = tk.Tk()
root.title("Control Panel")
root.style = ttk.Style()
root.style.theme_use("clam")
user = MainWindow(root)
root.mainloop()
If what you're really asking is how to replace an existing notebook with a new notebook, all you need to do is call destroy() on the old notebook before creating the new one.
First, define self.tabControl to None somewhere in MainWindow.__init__. Then, in tabtop you can delete the old notebook before creating the new one:
def tabtop(self):
if self.tabControl is not None:
self.tabControl.destroy()
...
I'm aiming to make a login program but the only part that confuses me is how to make the frames.I need 3 different frames but I neither know how to make a frame other the then like this:
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
and I can only make labels and widgets using that single mainframe. As far as making another one, it is beyond me. I need to know exactly place widets inside of each frame and even after creating frames I don't know how to place stuff on the grid. Would I go for the overall grid, or does something change after making the grid. I'm using the following layout for making the frame. Basically i'm hoping for a crash course in frames. Any information i've gathered doesn't make sense to me, even after I tried to put it into code.
I've got the coding part down just not the frame part.
#Import tkinter to make gui
from tkinter import *
from tkinter import ttk
import codecs
def login(*args
):
file = open("rot13.txt", "r")
lines = file.readlines()
uname = user.get()
pword = pw.get()
for i in lines:
x = i.split()
if codecs.encode(uname,'rot13') == x[0] and codecs.encode(pword,'rot13') == x[1]:
result.set("Successful")
break;
else:
result.set("Access Denied")
root = Tk()
root.title("Login")
#Configures column and row settings and sets padding
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
user = StringVar()
pw = StringVar()
result = StringVar()
user_entry = ttk.Entry(mainframe, width=20, textvariable=user)
user_entry.grid(column=2, row=1, sticky=(W, E))
pw_entry = ttk.Entry(mainframe, width=20, textvariable=pw)
pw_entry.grid(column=2, row=2, sticky=(W, E))
ttk.Label(mainframe, text="Username ").grid(column=1, row=1, sticky=W)
ttk.Label(mainframe, text="Password ").grid(column=1, row=2, sticky=W)
ttk.Label(mainframe, text="").grid(column=1, row=3, sticky=W)
ttk.Label(mainframe, text="Result").grid(column=1, row=4, sticky=W)
ttk.Label(mainframe, text="").grid(column=1, row=5, sticky=W)
ttk.Button(mainframe, text="Login", command=login).grid(column=3, row=6, sticky=W)
#Makes a spot to put in result
ttk.Label(mainframe, textvariable=result).grid(column=2, row=4, sticky=(W, E))
#Opens up with item selected and allows you to enter username without having to click it
user_entry.focus()
#Runs calculate if click enter
root.bind('<Return>', login)
root.mainloop()
I believe the key point that you are missing is that subframes of mainframe use mainframe as the parent and that widgets within subframes use the subframe as parent. Furthermore, you can then place the subframe within the mainframe and the subframe widgets within the subframe. You do not have to pass parents to .grid because each widget knows its parent. A simplified example:
from tkinter import *
root = Tk()
mainframe = Frame(root)
login = Frame(mainframe)
label = Label(login, text='label')
entry = Entry(login)
display = Frame(mainframe)
result = Label(display, text='display result')
mainframe.grid() # within root
login.grid(row=0, column=0) # within mainframe
label.grid(row=0, column=0) # within login
entry.grid(row=0, column=1) # within login
display.grid() # within mainfram
result.grid(row=2, column=0) # within display
I came up with the following code more as a reference to help me remember how to build GUI apps with TkInter. It runs great except when a click Button1 or any other widget whose command option is set to self.hello. As you can see in the code bellow, the hello function is like a place holder. While the button click works fine while running the script through IDLE, it simply causes the application to exit if you start the program by double-clicking the actual file test.pyw. My question is, why?
#Some guy somewhere
from tkinter import *
class Application:
def hello(self):
msg = messagebox.showinfo('Message Title','Message Body')
def __init__(self, parent):
parent.resizable(0,0)
parent.minsize(800, 400)
parent.title('Top Level')
# Global Padding pady and padx
pad_x = 0
pad_y = 0
# CASCADE MENU
# create a parent menu.
self.parentmenu1 = Menu(parent, tearoff=0)
#self.menubar1.add_command(label='Menu1', command=self.hello)
#create a child menu for parent menu.
self.parentmenu1_child1 = Menu(parent, tearoff=0)
self.parentmenu1_child1.add_command(label='Item1', command=self.hello)
self.parentmenu1_child1.add_command(label='Item2', command=self.hello)
self.parentmenu1_child1.add_command(label='Item3', command=self.hello)
#add child menu to parent menu.
self.parentmenu1.add_cascade(label='Menu1', menu=self.parentmenu1_child1)
#self.menubar1.add_separator()
# SINGLE MENU
# create a parent menu.
self.parentmenu1.add_command(label='Menu2', command=self.hello)
# SINGLE MENU
# create a parent menu.
self.parentmenu1.add_command(label='Menu3', command=self.hello)
# display the parent menu.
parent.config(menu=self.parentmenu1)
# Create controls
#create label
self.label1 = Label(parent, text='Label1')
#create textbox
self.textbox1 = Entry(parent)
#create button
self.button1 = Button(parent, text='Button1', command=self.hello)
#string variable to hold checkbox1 values.
self.str_checkbox1 = StringVar()
#create checkbox
self.checkbox1 = Checkbutton(parent, text='Checkbox1', variable=self.str_checkbox1, onvalue='on1', offvalue='off1')
#deselect checkbox1
self.checkbox1.deselect()
#string variable to hold checkbox2 values.
self.str_checkbox2 = StringVar()
#create checkbox
self.checkbox2 = Checkbutton(parent, text='Checkbox2', variable=self.str_checkbox2, onvalue='on2', offvalue='off2')
#deselect checkbox2
self.checkbox2.deselect()
#???? ..what sets the groupbox apart from others. primary key???!!
self.str_radiobutton1 = StringVar()
#command= parameter missing.
self.radiobutton1 = Radiobutton(parent, text='Radio 1', variable=self.str_radiobutton1, value='a')
self.radiobutton2 = Radiobutton(parent, text='Radio 2', variable=self.str_radiobutton1, value='b')
self.radiobutton1.select()
#create a list of options.
optionList = ('Option1', 'Option2', 'Option3')
#string variable to hold optionlist values.
self.str_optionmenu1 = StringVar()
#associate string variable with optionlist
self.str_optionmenu1.set(optionList[0])
#create optionmenu
self.optionmenu1 = OptionMenu(parent, self.str_optionmenu1, *optionList)
#create a frame
self.frame1 = Frame(parent)
#create a text.
self.textarea1 = Text(self.frame1, width=20, height=10)
#align text left and fill frame with it.
self.textarea1.pack(side=LEFT, fill=Y)
#create a scrollbar.
self.scrollbar1 = Scrollbar(self.frame1)
#align scrollbar right and fill frame with it.
self.scrollbar1.pack(side=RIGHT, fill=Y)
#what is going to be scrolled?
self.scrollbar1.config(command=self.textarea1.yview)
#set textarea scrollbar.
self.textarea1.config(yscrollcommand=self.scrollbar1.set)
#align frame left and fill.
self.frame1.pack(side=LEFT, fill=Y)
#create a frame
self.frame2 = Frame(parent)
#create a text.
self.listbox1 = Listbox(self.frame2, width=20, height=10, activestyle='none', selectmode=SINGLE)
#create a list of items.
optionList = ('Item1', 'Item2', 'Item3', 'Item4', 'Item5', 'Item6', 'Item7', 'Item8', 'Item9', 'Item10', 'Item11')
#add items from list to listbox
for item in optionList:
self.listbox1.insert(END, item)
#align text left and fill frame with it.
self.listbox1.pack(side=LEFT, fill=Y)
#create a scrollbar.
self.scrollbar2 = Scrollbar(self.frame2)
#align scrollbar right and fill frame with it.
self.scrollbar2.pack(side=RIGHT, fill=Y)
#what is going to be scrolled?
self.scrollbar2.config(command=self.listbox1.yview)
#set textarea scrollbar.
self.listbox1.config(yscrollcommand=self.scrollbar2.set)
#align frame left and fill.
self.frame2.pack(side=LEFT, fill=Y)
# Place controls inside of grid
self.label1.grid(row=0, column=0, padx=pad_x, pady=pad_y, sticky=W)
self.textbox1.grid(row=0, column=1, padx=pad_x, pady=pad_y, sticky=W)
self.button1.grid(row=1, column=0, padx=pad_x, pady=pad_y, sticky=W)
self.checkbox1.grid(row=1, column=1, padx=pad_x, pady=pad_y, sticky=W)
self.checkbox2.grid(row=1, column=2, padx=pad_x, pady=pad_y, sticky=W)
self.optionmenu1.grid(row=2, column=0, padx=pad_x, pady=pad_y, sticky=W)
self.frame1.grid(row=2, column=1, padx=pad_x, pady=pad_y, sticky=W)
self.radiobutton1.grid(row=3, column=0, padx=pad_x, pady=pad_y, sticky=W)
self.radiobutton2.grid(row=3, column=1, padx=pad_x, pady=pad_y, sticky=W)
self.frame2.grid(row=4, column=0, padx=pad_x, pady=pad_y, sticky=W)
if __name__ == '__main__':
parent = Tk()
app = Application(parent)
parent.mainloop()
Alright. Apparently tkMessageBox has been renamed to messagebox in Python 3.x. Also this
module is not available in tkinter so even though a developer might use:
from tkinter import *
..he/she would still need to:
from tkinter import messagebox