Python - How to assign OpenMenu choice as a List? - python

I have created Frame with Entry widget to ask user to input his Username and select a team, that he want to join in and also I have created an OpenMenu Widget with 4 teams that user can join.
I want to know, how to assign list to OpenMenu variations as a list. For example: Selection "Team 1" = team1Members etc.
Also I want to know, how to assign data from Entry Widget to appropriate list. For example, if user have selected "Team 1", his username will append to team1Members list.
from tkinter import *
import tkinter.ttk as ttk
team1Members = []
team2Members = []
team3Members = []
team4Members = []
class CollegeApp(Tk):
def __init__(self):
Tk.__init__(self)
container = ttk.Frame(self)
container.pack(side="top", fill="both", expand=True)
self.frames = {}
for F in (StartPage, selectionPage, TeamsPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(ttk.Frame):
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
self.startMenu()
def startMenu(self):
heading = Label(self, text="College Tournament Points\n Count Software",
font=('Arial', 25))
heading.grid(row=0, column=0, columnspan=2, padx=240, pady=40)
start_Btn = Button(self, text="Start", font="Arial 16", width=8,
command=lambda: self.controller.show_frame(selectionPage))
start_Btn.grid(row=1, column=0, padx=30, pady=5)
exit_Btn = Button(self, text="EXIT", font="Arial 16", width=8,
command=self.controller.destroy)
exit_Btn.grid(row=1, column=1, padx=30, pady=5)
def starting_Program(self):
pass
class selectionPage(ttk.Frame):
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
self.teamSelect()
def teamSelect(self):
heading = Label(self, text="Become a member of a Team",
font=('Arial', 25))
heading.grid(row=0, column=0, columnspan=2, padx=200, pady=40)
teams = Button(self, text="Teams", font="Arial 24", width=15,
command=lambda: self.controller.show_frame(TeamsPage))
teams.grid(row=1, column=0, padx=270, pady=5)
class TeamsPage(ttk.Frame):
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
self.userEntry()
def userEntry(self):
headingTest = Label(self, text="Enter your Username:", font="Arial 20")
headingTest.grid(row=0, column=0, pady=0)
usernameEnter = Entry(self, width=40)
usernameEnter.grid(row=0, column=1, padx=2, pady=10)
UserName = StringVar(self)
UserName.set("Team1")
AdditionalText = Label(self, text="Please select a team:", font="Arial 18")
AdditionalText.grid(row=1, column=0, sticky=W, pady=15)
teamSelection = OptionMenu(self, UserName, "Team1", "Team2", "Team3", "Team 4") # How to link those variations to team list? For example: Team 1 = team1Members?
teamSelection.grid(row=1, column=1, sticky=W)
confirmBtn = Button(self, text="Submit", font="Arial 16",
command=()) # Command to Save username in teamXMembers list. Depends on the user selection
confirmBtn.config(height=4, width=12)
confirmBtn.grid(row=2, column=2, sticky=E, padx=65, pady=300)
if __name__ == '__main__':
app = CollegeApp()
app.geometry("800x500")
app.title('Points Counter')
app.mainloop()
Screenshot of this window:

There are few ways that could achieve this. The First would be to create a list of teams and unpack them using * in optionMenu then use if else condition to check which list to append to.
Here is a demo
class TeamsPage(ttk.Frame):
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
self.teamList = ["Team1", "Team2", "Team3", "Team 4"]
self.userEntry()
def userEntry(self):
...
self.usernameEnter = Entry(self, width=40)
self.usernameEnter.grid(row=0, column=1, padx=2, pady=10)
self.userName = StringVar(self)
self.userName.set("Team1")
teamSelection = OptionMenu(self, self.userName, *self.teamList)
teamSelection.grid(row=1, column=1, sticky=W)
confirmBtn = Button(self, text="Submit", font="Arial 16",
command= self.updateTeamList) # Command to Save username in teamXMembers list. Depends on the user selection
...
def updateTeamList(self):
if self.userName.get() == self.teamList[0]:
team1Members.append(self.usernameEnter.get())
elif self.userName.get() == self.teamList[1]:
team2Members.append(self.usernameEnter.get())
...
but a better way would be to create a dictionary. something as shown
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
self.teamList = {"Team1": team1Members , "Team2": team2Members,
"Team3":team3Members, "Team 4": team4Members}
self.userEntry()
def userEntry(self):
...
self.usernameEnter = Entry(self, width=40)
self.usernameEnter.grid(row=0, column=1, padx=2, pady=10)
self.userName = StringVar(self)
self.userName.set("Team1")
AdditionalText = Label(self, text="Please select a team:", font="Arial 18")
AdditionalText.grid(row=1, column=0, sticky=W, pady=15)
teamSelection = OptionMenu(self, self.userName, *self.teamList.keys())
teamSelection.grid(row=1, column=1, sticky=W)
confirmBtn = Button(self, text="Submit", font="Arial 16",
command= self.updateTeamList) # Command to Save username in teamXMembers list. Depends on the user selection
...
def updateTeamList(self):
self.teamList[self.userName.get()].append(self.usernameEnter.get())

Related

Value submitted through tkinter login page is not reflected in the database

I am designing an app in python 3 and I am using xampp as database.
I have a LogIn Page and Home Page. The idea is that when I login by entering the credentials there is navigation between the pages and the credentials are reflected in the database. Here the pages are treated as frames. I am able to navigate between the frames.
My code shows no error but the entry made in the log in page is not reflected in the database.
The code is as shown below
import tkinter as tk
from tkinter import ttk
import mysql.connector
from tkinter import messagebox
class App(tk.Tk):
bg_img_path = "images\\bg9.png"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.geometry("1500x750")
main_frame = tk.Frame(self, width=200, height=50, highlightbackground="black", highlightthickness=1,
background="#e6ffe6")
main_frame.pack(side='top', fill='both', expand='True')
main_frame.grid_rowconfigure(0, weight=1)
main_frame.grid_columnconfigure(0, weight=1)
self.bkgr_image = tk.PhotoImage(file=self.bg_img_path)
self.frames = {}
for F in (LoginPage,HomePage):
page_name = F.__name__
frame = F(main_frame, self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky='nsew')
self.show_frame("LoginPage")
def show_frame(self, container):
frame = self.frames[container]
frame.tkraise()
class BasePage(tk.Frame):
def __init__(self, parent, controller):
super().__init__(parent)
self.controller = controller
label_bkgr = tk.Label(self, image=controller.bkgr_image)
label_bkgr.place(x=0, y=0)
class LoginPage(BasePage):
def __init__(self, parent, controller):
super().__init__(parent, controller)
login_frame = tk.Frame(self, width=200, height=50, highlightbackground="black", highlightthickness=1,
background="#e6ffe6")
login_frame.grid(row=400, column=20, padx=500, pady=250)
self.label_title = tk.Label(login_frame, text="Log In", font=("Helvetica", 40), bg="#e6ffe6")
self.label_title.grid(row=0, column=20, padx=10, pady=10)
self.label_username = tk.Label(login_frame, text="Username", font=("Helvetica", 20), bg="#e6ffe6")
self.label_username.grid(row=50, column=20, padx=10, pady=10)
self.entry_username = tk.Entry(login_frame, width=15, font=("Helvetica", 20))
self.entry_username.grid(row=50, column=30, padx=10, pady=10)
self.label_password = tk.Label(login_frame, text="Password", font=("Helvetica", 20), bg="#e6ffe6")
self.label_password.grid(row=60, column=20, padx=10, pady=10)
self.entry_password = tk.Entry(login_frame, width=15, font=("Helvetica", 20))
self.entry_password.grid(row=60, column=30, padx=10, pady=10)
self.login_button = tk.Button(login_frame, text="Log In", command=lambda: [self.submit,self.controller.show_frame("HomePage")], font=("Helvetica", 20),
bg="#e6ffe6")
self.login_button.grid(row=70, column=25, padx=10, pady=10)
def submit(self):
self.u_name = self.entry_username.get()
self.p_word = self.entry_password.get()
employee = mysql.connector.connect(host="localhost", user="root", password="", database="edatabase")
cursor_variable = employee.cursor()
cursor_variable.execute("INSERT INTO login VALUES ('" + self.u_name + "','" + self.p_word + "')")
employee.commit()
employee.close()
messagebox.showinfo("Log In", "Succesfull")
class HomePage(BasePage):
def __init__(self, parent, controller):
super().__init__(parent, controller)
#self.menubar = tk.Menu(self)
#self.menubar.add_command(label = "Home")
#self.menubar.add_command(label = "Careers")
label1 = ttk.Label(self, text='Home', font=("Helvetica", 20))
label1.pack(padx=10, pady=10)
app = App()
app.mainloop()
Any help is appreciated.
the error is resolved. I forgot to put (). Then it becomes
self.login_button = tk.Button(login_frame, text="Log In", command=lambda: [self.submit(),self.controller.show_frame("HomePage")], font=("Helvetica", 20),
bg="#e6ffe6")

Python - How to add information from dictionaries to listbox widget?

This is my first encounter with listboxes and I want to know how to insert the name of each team member into the corresponding listbox.
I have a dictionary called teams, and it's store data like that:
{'Team1': {'Aleks', Richard}, 'Team2': {'Louis'}, 'Team3': set(), 'Team4': set()}
I need to put set of names in particular listbox (ex. 'Team1' set should appear in the team1Members listbox).
I was trying to use .insert method to insert specific items from my dictionary, but I receive an error:
_tkinter.TclError: bad listbox index ".!frame.!listcheckpage": must be active, anchor, end, #x,y, or a number
My code:
from tkinter import *
from tkinter import messagebox
import tkinter.ttk as ttk
import time
class CollegeApp(Tk):
def __init__(self):
Tk.__init__(self)
container = ttk.Frame(self)
container.pack(side="top", fill="both", expand=True)
self.frames = {}
for F in (StartPage, TeamsPage, successfullAddTeam, selectionPage, listCheckPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
self.lift()
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(ttk.Frame):
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
self.startMenu()
def startMenu(self):
heading = Label(self, text="College Tournament Points\n Count Software",
font=('Arial', 25))
heading.grid(row=0, column=0, columnspan=2, padx=240, pady=40)
start_Btn = Button(self, text="START", font="Arial 16", width=8,
command=lambda: self.controller.show_frame(selectionPage))
start_Btn.grid(row=1, column=0, columnspan=2, padx=30, pady=5)
exit_Btn = Button(self, text="EXIT", font="Arial 16", width=8,
command=self.controller.destroy)
exit_Btn.grid(row=2, column=0, columnspan=2, padx=30, pady=5)
def starting_Program(self):
pass
class selectionPage(ttk.Frame):
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
self.teamSelect()
def teamSelect(self):
heading = Label(self, text="Select one of two options",
font=('Arial', 25))
heading.grid(row=0, column=0, columnspan=2, padx=250, pady=40)
teams = Button(self, text="Teams", font="Arial 24", width=15,
command=lambda: self.controller.show_frame(TeamsPage))
teams.grid(row=1, column=0, padx=270, pady=5)
class TeamsPage(ttk.Frame):
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
self.userEntry()
def userEntry(self):
headingTest = Label(self, text="Enter your UserName:", font="Arial 20")
headingTest.grid(row=0, column=0, pady=5, padx=5)
self.usernameEnter = Entry(self, width=40)
self.usernameEnter.grid(row=0, column=1, padx=5, pady=5)
self.TeamName = StringVar(self)
self.TeamName.set("Team1")
AdditionalText = Label(self, text="Please select a team:", font="Arial 18")
AdditionalText.grid(row=1, column=0, sticky=W, pady=15, padx=5)
self.team_names = list(teams.keys())[:-1]
self.teamSelection = OptionMenu(self, self.TeamName, *self.team_names)
self.teamSelection.grid(row=1, column=1, sticky=W)
backBtn = Button(self, text="BACK", font="Arial 16",
command=lambda: self.controller.show_frame(StartPage))
backBtn.config(height=4, width=12)
backBtn.grid(sticky=W, row=2, column=0, pady=5, padx=5)
confirmBtn = Button(self, text="Confirm User", font="Arial 16",
command=self.confirm)
confirmBtn.config(height=4, width=12)
confirmBtn.grid(row=2, column=2, sticky=E, padx=45, pady=300)
def confirm(self):
if self.add_to_team():
time.sleep(0.2)
self.controller.show_frame(successfullAddTeam)
def add_to_team(self):
user = self.usernameEnter.get()
if len(user) == 0:
messagebox.showwarning(title='No user', message='Please enter a username!')
return
if self.usernameEnter.get():
time.sleep(0.1)
self.controller.show_frame(successfullAddTeam)
team_name = self.TeamName.get()
team = teams[team_name]
if user in team:
messagebox.showwarning(title='In team', message=f'{user} is already a member of {team_name}!')
team.add(user)
print(teams)
class successfullAddTeam(ttk.Frame):
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
self.userEntry()
def userEntry(self):
successText = Label(self, text="You have successfully joined to a team!", font="Arial 25")
successText.grid(row=0, column=0, columnspan=2, padx=180, pady=35)
newUser = Button(self, text="Add another user", font="Arial 16",
command=lambda: self.controller.show_frame(selectionPage))
newUser.config(height=3, width=12)
newUser.grid(row=1, column=0, columnspan=2, padx=200, pady=10)
checkList = Button(self, text="Check the lists", font="Arial 16",
command=lambda: self.controller.show_frame(listCheckPage))
checkList.config(height=3, width=12)
checkList.grid(row=2, column=0, columnspan=2, padx=200, pady=0)
#####################################Problem here###############################################
class listCheckPage(ttk.Frame):
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
self.userEntry()
def userEntry(self):
team1Members = Listbox(self)
team1Members.insert(self, teams['Team1'])
team1Members.config(height=13, width=20)
team1Members.grid(row=0, column=0, padx=10, pady=5, sticky=W)
team2Members = Listbox(self)
team2Members.insert(self, teams['Team2'])
team2Members.config(height=13, width=20)
team2Members.grid(row=0, column=1, padx=7, pady=5, sticky=W)
team3Members = Listbox(self)
team3Members.insert(self, teams['Team3'])
team3Members.config(height=13, width=20)
team3Members.grid(row=0, column=3, padx=7, pady=5, sticky=W)
team4Members = Listbox(self)
team4Members.insert(self, teams['Team4'])
team4Members.config(height=13, width=20)
team4Members.grid(row=0, column=4, padx=7, pady=5, sticky=W)
addUserBtn = Button(self, text="Add User", font="Arial 16",
command=lambda: self.controller.show_frame(selectionPage))
addUserBtn.config(height=3, width=18)
addUserBtn.grid(row=1, column=4, sticky=S)
if __name__ == '__main__':
teams = {}
for team in range(1, 5):
teams[f'Team{team}'] = set()
app = CollegeApp()
app.geometry("800x500")
app.title('Points Counter')
app.mainloop()
It is obvious that I am doing something wrong, and I would like to know how this issue can be properly resolved.

Calling functions from classes with inheritence

I'm sure i'm missing something with the class/inheritence understanding.
when i hit the submit button i get this error:
I tried many variations like changing the command in the button, changing masters, defining self.controller.
how can I make the submit button to work?
import tkinter as tk
import os
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.geometry("650x500")
self.title("Gil Shwartz GUI Project")
menu = tk.Frame(self, height=250, width=10, bg="black")
menu.pack(side=tk.LEFT, fill="both", anchor="w")
container = tk.Frame(self, height=250, width=270, relief="flat")
container.pack(side=tk.TOP, fill="both", expand=True)
output = tk.LabelFrame(self, text="Output", height=150, padx=5, pady=5)
output.pack(side=tk.BOTTOM, fill="both", anchor="s")
menu.grid_columnconfigure(0, weight=0)
menu.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(1, weight=1)
self.frames = ["StartPage", "MainWelcome", "testPing", "PageOne", "PageTwo"]
self.frames[0] = Menu(parent=menu, controller=self)
self.frames[1] = MainWelcome(parent=container, controller=self)
self.frames[2] = testPing(parent=container, controller=self)
self.frames[3] = PageOne(parent=container, controller=self)
self.frames[4] = PageTwo(parent=container, controller=self)
self.frames[0].grid(row=0, column=0, sticky="nsew")
self.frames[1].grid(row=0, column=0, sticky="nsew")
self.frames[2].grid(row=0, column=0, sticky="nsew")
self.frames[3].grid(row=0, column=0, sticky="nsew")
self.frames[4].grid(row=0, column=0, sticky="nsew")
self.show_frame(1)
def show_frame(self, page_name):
frame = self.frames[page_name]
print(frame)
frame.tkraise()
class Menu(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.menu = controller
button1 = tk.Button(self, text="Ping Test",
command=lambda: controller.show_frame(2))
button2 = tk.Button(self, text="Page Two",
command=lambda: controller.show_frame(4))
button3 = tk.Button(self, text="Quit",
command=lambda: Menu.terminate(self))
button1.pack(fill="both", expand=True)
button2.pack(fill="both", expand=True)
button3.pack(fill="both", expand=True)
button1.grid_columnconfigure(0, weight=1)
button2.grid_columnconfigure(0, weight=0)
button3.grid_rowconfigure(0, weight=0)
def terminate(self):
exit()
class MainWelcome(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.menu = controller
label = tk.Label(self, text="Text 1", bg="yellow")
label.pack(fill="x", expand=True)
label = tk.Label(self, text="Text 2", bg="yellow")
label.pack(fill="x")
class testPing(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.urlLabel = controller
urlLabel = tk.Label(self, text="Enter URL : ", padx=5, pady=5)
urlLabel.pack(anchor="w")
urlInputBox = tk.Entry(self)
urlInputBox.pack()
urlInputBox.grid_columnconfigure(0, weight=0)
clearLabel = tk.Label(self, text="Clear File?", padx=5, pady=5)
clearLabel.pack(anchor="w")
clearFile = tk.BooleanVar()
clearFile.set(False)
clearFileRadioYes = tk.Radiobutton(self, text="yes", value=True, var=clearFile,
command=lambda: testPing.callback(clearFile.get()))
clearFileRadioYes.pack(anchor="w")
clearFileRadioNo = tk.Radiobutton(self, text="no", value=False, var=clearFile,
command=lambda: testPing.callback((clearFile.get())))
clearFileRadioNo.pack(anchor="w")
urlSubmitButton = tk.Button(self, text="Submit",
command=lambda: testPing.pingURL(urlInputBox.get(),
testPing(clearFile.get())))
urlSubmitButton.pack(side=tk.RIGHT, anchor="e")
def callback(clearFile):
print(clearFile) # Debugging Mode - check Radio box Var.
def pingURL(self, host, clearFile):
outputFrameLabel = tk.LabelFrame(self, text="Output", height=35, width=150,
padx=5, pady=5, relief="solid")
outputFrameLabel.place(x=0, y=150)
file = fr'c:/users/{os.getlogin()}/Desktop/ping.txt'
label = tk.Label(outputLabel, text=f'Pinging {host} ...')
label.grid(row=0, column=0)
label.update()
if clearFile == True:
with open(file, 'w+') as output:
output.truncate(0)
sub.call(['ping', f'{host}'], stdout=output)
else:
with open(file, 'a') as output:
sub.call(['ping', f'{host}'], stdout=output)
output.close()
label.configure(text=f'Ping to {host} complete!')
# testPing.changeLabel(host)
# def changeLabel(self, host):
# myLabel = tk.Label.config(text=f"Ping to {host} Complete!")
# myLabel.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 1", bg="red")
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to page 2",
command=lambda: controller.show_frame(2))
button.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 2", bg="blue")
label.pack(side="top", fill="x", pady=10)
# button = tk.Button(self, text="Go to the start page",
# command=lambda: controller.show_frame(0))
# button.pack()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
here's a pic of the main window so you'll get a visual idea as well.
I think the error lies in the testPing class; in particular in these lines:
class testPing(tk.Frame):
...
clearFileRadioYes = tk.Radiobutton(self, text="yes", value=True, var=clearFile,
command=lambda: testPing.callback(clearFile.get()))
clearFileRadioYes.pack(anchor="w")
clearFileRadioNo = tk.Radiobutton(self, text="no", value=False, var=clearFile,
command=lambda: testPing.callback((clearFile.get())))
clearFileRadioNo.pack(anchor="w")
urlSubmitButton = tk.Button(self, text="Submit",
command=lambda: testPing.pingURL(urlInputBox.get(),
testPing(clearFile.get())))
You're inside testPing, so you should use self instead of using testPing explicitly. So, your code should be:
class testPing(tk.Frame):
...
clearFileRadioYes = tk.Radiobutton(self, text="yes", value=True, var=clearFile,
command=lambda: self.callback(clearFile.get()))
clearFileRadioYes.pack(anchor="w")
clearFileRadioNo = tk.Radiobutton(self, text="no", value=False, var=clearFile,
command=lambda: self.callback((clearFile.get())))
clearFileRadioNo.pack(anchor="w")
urlSubmitButton = tk.Button(self, text="Submit",
command=lambda: self.pingURL(urlInputBox.get(),
clearFile.get()))
Notice using self instead of testPing

Switching frame automatically in Tkinter

I am aware similar questions have been answered, but I have read them thoroughly and cannot find a solution for myself.
After the BMR_method is done, and either the if, elif, or else options has completed, I want it to automatically load a new class/frame: work . But I cannot figure out how to do this. I tried adding different variations of self.show_frame(work), also tried adding parent/controller parameters to the function but it will either tell me I am missing positional arguments or that the show_frame method doesn't exist. Please help.
import tkinter as tk
from decimal import Decimal
import time
LARGE_FONT = ("Verdana", 12)
def gender():
if var1.get() and var2.get():
print('Please only tick one box')
var1.set(0)
var2.set(0)
elif var1.get():
print('Male')
bmr_male()
elif var2.get():
print('Female')
bmr_female()
else:
print('Please tick male or female')
class theog(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
controller = self
container.pack(side='top', fill='both', expand= True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, BMR, work):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky='nsew')
self.show_frame(StartPage)
def show_frame(self, controller):
frame = self.frames[controller]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Start Page", width = 60)
label.pack()
button = tk.Button(self, text="Begin!",
command=lambda: controller.show_frame(BMR))
button.pack()
class BMR(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="BMR Calculator", width = 20)
label.grid(column=0, row=0, sticky='W')
label_height = tk.Label(self, text="Height (CM)")
label_height.grid(column=3, row=0, sticky='E')
label_weight = tk.Label(self, text="Weight (KG)")
label_weight.grid(column=3, row=1, sticky='E')
label_age = tk.Label(self, text="Age")
label_age.grid(column=3, row=2, sticky='E')
self.text_height = tk.Entry(self, width=20, bg="white")
self.text_height.grid(row=0, column=4, sticky='W')
self.text_weight = tk.Entry(self, width=20, bg="white")
self.text_weight.grid(row=1, column=4, sticky='W')
self.text_age = tk.Entry(self, width=20, bg="white")
self.text_age.grid(row=2, column=4, sticky='W')
self.resultvar = tk.StringVar()
self.result = tk.Label(self, textvariable=self.resultvar)
self.result.grid(row=3, column=1)
self.var1 = tk.StringVar()
self.var1.set(None)
tk.Radiobutton(self, text="Male", bg='white', value='male', variable=self.var1).grid(row=0, column=1, sticky='S')
tk.Radiobutton(self, text="Female", bg='white', value='female', variable=self.var1).grid(row=1, column=1, sticky='S')
tk.Button(self, text="Submit!", width=6, command=self.bmr_method).grid(row=3, column=0, sticky='W')
def bmr_method(self, Entry=None):
if self.text_height.get() and self.text_weight.get() and self.text_age.get() and self.var1.get() == 'male':
bh = float(self.text_height.get()) * 5.0033
bw = float(self.text_weight.get()) * 13.7516
ba = float(self.text_age.get()) * 6.7550
bmr = float(66.4730 + bh + bw - ba)
self.resultvar.set('Your BMR is: ' + str(bmr))
elif self.text_height.get() and self.text_weight.get() and self.text_age.get() and self.var1.get() == 'female':
bh = float(self.text_height.get()) * 1.8496
bw = float(self.text_weight.get()) * 9.5634
ba = float(self.text_age.get()) * 4.6756
bmr = float(655.095 + bh + bw - ba).round(1)
self.resultvar.set('Your BMR is:' + str(bmr) +'\n press continue to find out \n your maintenance calories')
else:
'Please ensure all information has been entered and click again'
self.resultvar.set('Please ensure all \n information has been \n entered and click again')
self.controller.show_frame(work) #I WANT TO OPEN THE CLASS BELOW AFTER THIS METHOD HAS FINISHED
class work(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
controller = self
root = theog()
root.mainloop()
First, your class needs accept and save a reference to the controller so that you can access it later:
class BMR(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
...
Then, you simply need to call the controller method show_frame:
self.controller.switch_frame(work)

Getting a function to "wait" for values in multi-frame Tkinder app

I have a script that creates a build in TeamCity. I am trying to create a gui that accomplishes this using Tkinder. There are multiple steps to take (ie get credentials -> input buildname -> add template - > etc), so I am using multiple frames to create the steps using the show_frame() command. My problem is the following: I make multiple REST calls, so the first step is getting the user's username and password. However, since all the pages are initialized when the program starts, all my methods that make REST calls error because they don't have the credentials yet.
How can I get the subsequent steps (and their methods) to wait for the user to input username and password?
From the code below, (in the PageOne class) I am trying to get a list of projects from BitBcuket through a REST call so I can dynamically add menu items to a menu, but I can't figure out how to wait to get the username and password.
import json
import requests
import Tkinter as tk
import tkMessageBox
TITLE_FONT = ("Arial", 18, "bold")
class CreateBuild(tk.Tk):
def __init__(self, *args, **kwargs):
self.username = None
self.password = None
self.bit_projects = None
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, PageOne, PageTwo):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
def authenticate(self, username, password):
r = requests.head('https://source.amirsys-int.com/projects', auth=(username, password))
if r.status_code == 405:
self.username = username
self.password = password
self.show_frame("PageOne")
else:
tkMessageBox.showinfo("Error", "Incorrect username and/or password.\nPlease enter your Crowd username and "
"password.")
def get_bitbucket_projects(self):
r = requests.get('https://source.amirsys-int.com/rest/api/1.0/projects', auth=(self.username,
self.password))
j = json.loads(r.text)
size = j['size']
repo_dic = {}
for i in range(0, size):
name = j['values'][i]['name']
repo_id = j['values'][i]['key']
repo_dic[name] = repo_id
self.bit_project = repo_dic
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
instructions = tk.Label(self, text="Please enter your Crowd credentials", font=TITLE_FONT)
instructions.grid(column=1, row=1, columnspan=3, padx=30, pady=30)
username = tk.Label(self, text="Crowd Username: ")
username.grid(column=1, row=2, columnspan=2)
password = tk.Label(self, text="Crowd Password: ")
password.grid(column=1, row=3, columnspan=2)
username_entry = tk.Entry(self)
username_entry.grid(column=3, row=2)
password_entry = tk.Entry(self, show="*")
password_entry.grid(column=3, row=3)
button = tk.Button(self, text="Next", command=lambda: controller.authenticate(username_entry.get(),
password_entry.get()))
button.grid(column=4, row=4, padx=10, pady=10)
self.grid_rowconfigure(5, weight=1)
self.grid_columnconfigure(5, weight=1)
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
instructions = tk.Label(self, text="Enter build information", font=TITLE_FONT)
instructions.grid(column=1, row=1, columnspan=3, padx=30, pady=30)
build_name = tk.Label(self, text="Build Name: ")
build_name.grid(column=1, row=2, columnspan=2)
build_name_entry = tk.Entry(self)
build_name_entry.grid(column=3, row=2)
project_key = tk.Label(self, text="BitBucket Project: ", anchor="w")
project_key.grid(column=1, row=3, columnspan=2)
project_menu = tk.Menubutton(self, text="Project", anchor="w")
project_menu.grid(column=3, row=3, columnspan=2)
project_menu.menu = tk.Menu(project_menu)
for key, value in controller.bit_projects:
project_menu.menu.add_checkbutton(label=key, variable=value)
self.grid_rowconfigure(4, weight=1)
self.grid_columnconfigure(4, weight=1)
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
if __name__ == "__main__":
app = CreateBuild()
app.geometry("800x600")
app.title("Create TeamCity Build")
app.mainloop()
You need to move that code out of the __init__ method (which runs when the program starts) and into the method that gets called when the frame is shown: tkraise().
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
instructions = tk.Label(self, text="Enter build information", font=TITLE_FONT)
instructions.grid(column=1, row=1, columnspan=3, padx=30, pady=30)
build_name = tk.Label(self, text="Build Name: ")
build_name.grid(column=1, row=2, columnspan=2)
build_name_entry = tk.Entry(self)
build_name_entry.grid(column=3, row=2)
project_key = tk.Label(self, text="BitBucket Project: ", anchor="w")
project_key.grid(column=1, row=3, columnspan=2)
self.project_menu = tk.Menubutton(self, text="Project", anchor="w")
self.project_menu.grid(column=3, row=3, columnspan=2)
self.project_menu.menu = tk.Menu(self.project_menu)
self.grid_rowconfigure(4, weight=1)
self.grid_columnconfigure(4, weight=1)
def tkraise(self):
for key, value in self.controller.bit_projects:
self.project_menu.menu.add_checkbutton(label=key, variable=value)
tk.Frame.tkraise(self) # call the superclass to actually raise the frame

Categories

Resources