Just a quick question. I've been researching online and I can't seem to find the answer.
How do you append an element to an object list?
from tkinter import *
class Movie:
def __init__(self, movie, ratings):
self.movie = movie
self.ratings = ratings
class MovieRaterGUI:
def __init__(self, parent):
self.counter = 0
self.index = 0
#variable set up
self.v = StringVar()
self.v.set(" ")
#frames used so you can easily switch between rating frame and summary frame - keeping the search frame
rating_frame = Frame(root)
search_frame = Frame(root)
rating_frame.pack(side="top", expand=True)
search_frame.pack(side="bottom", expand=True)
#rating frame
#list of ratings for movies
self.movies = [
Movie("The Hobbit", ["No Rating", "Forget it", "2", "3", "4", "Must See"]),
Movie("Coraline", ["No Rating", "Forget it", "2", "3", "4", "Must See"]),
Movie("Love, Rosie", ["No Rating", "Forget it", "2", "3", "4", "Must See"])]
#labels
self.movie_label = Label(rating_frame, text = "Please Rate:", borderwidth = 10)
self.current_movie = Label(rating_frame, text = self.movies[self.counter].movie, borderwidth = 10)
self.rating_label = Label(rating_frame, text = "Your rating:", borderwidth = 10)
self.movie_label.grid(row = 0, column = 0, sticky = W)
self.current_movie.grid(row = 0, column = 1, sticky = W)
self.rating_label.grid(row = 1, column = 0, sticky = W)
self.num_choices = (self.movies[self.index].ratings)
for i in range(len(self.num_choices)):
self.option = Radiobutton(rating_frame, variable = self.v, value = i, text = self.num_choices[i], borderwidth = 10)
self.option.grid(row = i+1, column = 1, sticky = W)
next_btn = Button(rating_frame, text = "Next", borderwidth = 10, command = self.next_movie)
previous_btn = Button(rating_frame, text = "Previous", borderwidth = 10, command = self.previous_movie)
next_btn.grid(row = 7, column = 1, sticky = W)
previous_btn.grid(row = 7, column = 0, sticky = W)
#search frame
self.search_label = Label(search_frame, text = "Search for movies with a rating of:", borderwidth = 10)
self.search_label.grid(row=0, column=0, columnspan=len(self.num_choices))
for i in range(len(self.num_choices)):
option = Radiobutton(search_frame, variable = self.v, value = i, text = self.num_choices[i])
option.grid(row = 1, column = i, sticky = W)
show_btn = Button(search_frame, text = "Show", borderwidth = 10)
show_btn.grid(row = 3, column = 0, columnspan = len(self.num_choices))
def next_movie(self):
self.movies.append(self.option)
self.counter +=1
self.current_movie.configure(text = self.movies[self.counter].movie)
def previous_movie(self):
self.movies.remove(self.option)
self.counter -=1
self.current_movie.configure(text = self.movies[self.counter].movie)
if __name__ == "__main__":
root = Tk()
root.title("Movie Ratings")
radiobuttons = MovieRaterGUI(root)
root.mainloop()
I'm trying to add the radio button that the user clicks on to the Movie Object lists for each list in the self.movies list. I am trying to do this when the user clicks the next or previous button.
Thank you!
Try to use setattr
Ex: setattr(object, 'field', value)
You can append the list by .append()
For example
a = [1,2,3,4,5]
a.append(6)
print(a)
Result:
[1,2,3,4,5,6]
Now to insert in different positions
In python first position is [0]
a = [1,2,3,4,5]
a.insert(1,6)
print(a)
Result:
[1,6,2,3,4,5]
Related
currently working on an API-based F1 drivers' app using Python and Tkinter.
The issue I'm facing is that contents from previous searches appear on forthcoming content.
Visually, the issue can be best represented here, where the new content appears on top of the old content, which is no good.
To solve this problem, I know that logically, there should be some approach where when user presses search_button, the button should be attempting to clear the previous search's content in main_frame and then recreate main_frame with the new content.
Generally, it's not too difficult to clear content in a frame, since that's through using w_info and the .destroy() method, but I don't know how to recreate a frame with new content. In other words, I'm having trouble programming out the logic (perhaps the logic should be clearer or there should be different logic)
Here's the code:
#Go to
from tkinter import *
from tkinter import ttk
from PIL import ImageTk, Image
from tkinter import messagebox
import requests
import json
root = Tk()
root.geometry("800x300")
root.title("F1 Desktop Application")
root.iconbitmap("formula1_logo.ico")
#generate 2022 drivers-list [can scale to drivers-list by changing the]
drivers_list_request = requests.get("http://ergast.com/api/f1/2022/drivers.json")
#initialize empty-list
drivers_list = []
drivers_list_object = json.loads(drivers_list_request.content)
for elements in drivers_list_object["MRData"]["DriverTable"]["Drivers"]:
drivers_list.append(elements["givenName"] + " " + elements["familyName"])
# Update the Entry widget with the selected item in list
def check(e):
v= entry_box.get()
if v=='':
hide_button(menu)
else:
data=[]
for item in drivers_list:
if v.lower() in item.lower():
data.append(item)
update(data)
show_button(menu)
def update(data):
# Clear the Combobox
menu.delete(0, END)
# Add values to the combobox
for value in data:
menu.insert(END,value)
def fillout(event):
try:
entry_box.delete(0,END)
entry_box.insert(0,menu.get(menu.curselection()))
hide_button(menu)
#handle a complete deletion of entry-box via cursor double tap
except:
pass
def hide_button(widget):
widget.grid_remove()
def show_button(widget):
widget.grid()
def full_name():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/drivers/{}.json".format(lower_user_input))
response_object = json.loads(response.content)
name = response_object["MRData"]["DriverTable"]["Drivers"][0]["givenName"] + " " + response_object["MRData"]["DriverTable"]["Drivers"][0]["familyName"]
driver_name_label.configure(text = name)
def team():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/current/drivers/{}/constructors.json".format(lower_user_input))
response_object = json.loads(response.content)
team = response_object["MRData"]["ConstructorTable"]["Constructors"][0]["name"]
team_api = Label(main_frame, text = team, font = ("Arial", 10))
team_api.grid(row = 1, column = 1)
def driver_code():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/drivers/{}.json".format(lower_user_input))
response_object = json.loads(response.content)
code = response_object["MRData"]["DriverTable"]["Drivers"][0]["code"]
code_api = Label(main_frame, text = code, font = ("Arial", 10))
code_api.grid(row = 3, column = 1, sticky = W)
def nationality():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/drivers/{}.json".format(lower_user_input))
response_object = json.loads(response.content)
nationality = response_object["MRData"]["DriverTable"]["Drivers"][0]["nationality"]
nationality_api = Label(main_frame, text = nationality, font = ("Arial", 10))
nationality_api.grid(row = 2, column = 1, sticky = W)
def wins():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/drivers/{}/results/1.json".format(lower_user_input))
response_object = json.loads(response.content)
wins = response_object["MRData"]["total"]
wins_api = Label(main_frame, text = wins, font = ("Arial", 10))
wins_api.grid(row = 4, column = 1, sticky = W)
def poles():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/drivers/{}/qualifying/1.json".format(lower_user_input))
response_object = json.loads(response.content)
poles = response_object["MRData"]["total"]
poles_api = Label(main_frame, text = poles, font = ("Arial", 10))
poles_api.grid(row = 2, column = 3, sticky = W, padx = 15)
def podiums():
lower_user_input = grab_user_input()
#podiums is sum of 1st, 2nd, 3rd place finishes
#####DRY principle; let's reuse the code from wins()
######noticing how maybe should create a separate function which "places" the widget
#######for now, reuse the code
#1st place finishes
response = requests.get("http://ergast.com/api/f1/drivers/{}/results/1.json".format(lower_user_input))
response_object = json.loads(response.content)
#convert wins to int
wins = int(response_object["MRData"]["total"])
#2nd place finishes
response_ii = requests.get("http://ergast.com/api/f1/drivers/{}/results/2.json".format(lower_user_input))
response_ii_object = json.loads(response_ii.content)
response_ii_amount = int(response_ii_object["MRData"]["total"])
#3rd place finishes
response_iii = requests.get("http://ergast.com/api/f1/drivers/{}/results/3.json".format(lower_user_input))
response_iii_object = json.loads(response_iii.content)
response_iii_amount = int(response_iii_object["MRData"]["total"])
podiums = str(wins + response_ii_amount + response_iii_amount)
podiums_api = Label(main_frame, text = podiums, font = ("Arial", 10))
podiums_api.grid(row = 1, column = 3, padx = 15, sticky = W)
def championships():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/drivers/{}/driverStandings/1/seasons.json".format(lower_user_input))
response_object = json.loads(response.content)
championships = response_object["MRData"]["total"]
championships_api = Label(main_frame, text = championships, font = ("Arial", 10))
championships_api.grid(row = 3, column = 3, padx = 15, sticky = W)
def standing():
lower_user_input = grab_user_input()
response = requests.get("http://ergast.com/api/f1/current/drivers/{}/driverStandings.json".format(lower_user_input))
response_object = json.loads(response.content)
position = response_object["MRData"]["StandingsTable"]["StandingsLists"][0]["DriverStandings"][0]["position"]
points = response_object["MRData"]["StandingsTable"]["StandingsLists"][0]["DriverStandings"][0]["points"]
standing = "{} ({} pts)".format(position, points)
standing_api = Label(main_frame, text = standing, font = ("Arial", 10))
standing_api.grid(row = 4, column = 3, padx = 15, sticky = W)
def grab_user_input():
user_input = entry_box.get()
lower_user_input = user_input.lower().split(" ")[1]
return lower_user_input
def search():
#slow run-time is simply due to the multiple api calls made
#perhaps less-so due to not completely following DRY principles
full_name()
team()
driver_code()
nationality()
wins()
poles()
podiums()
championships()
standing()
show_button(main_frame)
left_frame = LabelFrame(root, width = 275, height = 300)
left_frame.grid(row = 1, column = 0, sticky = SE)
left_frame.grid_propagate(False)
search_label = Label(left_frame, text = "Search Driver", font = ("Arial bold", 12))
search_label.grid(row = 0, column = 0, pady = 10)
entry_box = Entry(left_frame, bd = 5)
entry_box.grid(row = 1, column = 0, padx = 35, pady = 40)
entry_box.bind('<KeyRelease>',check)
search_button = Button(left_frame, text = "search", command = search)
search_button.grid(row = 1, column = 1, padx = 15)
menu= Listbox(left_frame, height = 7)
menu.grid(row = 2, column = 0)
menu.bind("<<ListboxSelect>>",fillout)
main_frame = LabelFrame(root, width = 575, height = 300)
main_frame.grid(row = 1, column = 1, sticky = SE)
main_frame.grid_propagate(False)
driver_name_label = Label(main_frame, text = "Driver", font = ("Arial", 15))
driver_name_label.grid(row = 0, column = 0,pady = 30)
team_label = Label(main_frame, text = "TEAM", font = ("Arial", 10))
team_label.grid(row = 1, column = 0, sticky = W)
nationality_label = Label(main_frame, text = "NATIONALITY", font = ("Arial", 10))
nationality_label.grid(row = 2, column = 0, sticky = W)
driver_code_label = Label(main_frame, text = "DRIVER CODE", font = ("Arial", 10))
driver_code_label.grid(row = 3, column = 0, sticky = W)
wins_label = Label(main_frame, text = "WINS", font = ("Arial", 10))
wins_label.grid(row = 4, column = 0, sticky = W)
podiums_label = Label(main_frame, text = "PODIUMS", font = ("Arial", 10))
podiums_label.grid(row = 1, column = 2, sticky = W, padx = 15)
poles_label = Label(main_frame, text = "POLES", font = ("Arial", 10))
poles_label.grid(row = 2, column = 2, sticky = W, padx = 15)
world_championships_label = Label(main_frame, text = "WORLD CHAMPIONSHIPS", font = ("Arial", 10))
world_championships_label.grid(row = 3, column = 2, padx = 15, sticky = W)
current_standing_label = Label(main_frame, text = "F1 2022 STANDING", font = ("Arial", 10))
current_standing_label.grid(row = 4, column = 2, padx = 15, sticky = W)
hide_button(menu)
hide_button(main_frame)
root.mainloop()
Would appreciate the help! If there are any follow-up questions for clarity, let me know!
Thanks, Safwan
im kinda new to tkinter and while working on a school project ive stumbbled a problem, the button i use to change a label cant be used more than once.
here is the full code:
from tkinter import *
import random, time
dic = {}
def pDic(dic):
print(dic)
def add(dic):
org = orgEntry.get()
tran = tranEntry.get()
dic[org] = tran
tranEntry.delete(0,END)
orgEntry.delete(0,END)
return dic
def clear():
labOrg.grid_remove()
labTran.grid_remove()
orgEntry.grid_remove()
tranEntry.grid_remove()
save.grid_remove()
printDic.grid_remove()
train.grid_remove()
def pMain(dic):
global practiceBtn
clear()
i=0
kList = list(dic)
random.shuffle(kList)
practiceEntry = Entry(app)
practiceEntry.grid(row = 1 , column = 1)
labPractice = Label(app, text = "Enter translation for: " + kList[i] )
labPractice.grid(row = 0 , column = 1, padx = 200)
practiceBtn = Button(app, text = "Check", command = lambda : pLoop(i,kList,labPractice,dic,practiceEntry.get()))
practiceBtn.grid(row = 2 , column = 1)
def pLoop(i,kList, labPractice, dic ,entered):
if entered== dic[kList[i]]:
i+=1
next(i,kList,labPractice)
def next(i,kList,labPractice):
labPractice.grid_remove()
labPractice = Label(app, text = "Enter translation for: " + kList[i] )
labPractice.grid(row = 0 , column = 1, padx = 200)
app = Tk()
app.geometry('600x450+1000+60')
app.title("Dictionary")
labOrg = Label(app, text = "Enter Word")
labOrg.grid()
orgEntry = Entry(app)
orgEntry.grid(padx = 20)
labTran = Label(app, text = "Enter Translation")
labTran.grid(row = 0, column = 1, padx = 70)
tranEntry = Entry(app)
tranEntry.grid(row = 1, column = 1, padx = 70)
save = Button(app, text = "Save to dictionary", command = lambda : add(dic))
save.grid(row = 2 ,column = 1,columnspan = 1, pady=10, padx=50)
printDic = Button(app, text = "print dictionary", command = lambda : pDic(dic))
printDic.grid()
train = Button(app, text = "Train", command = lambda : pMain(dic))
train.grid(row = 2, pady = 20, padx = 50)
app.mainloop()
right now its kinda messy (and unfinished :p)but id be thankfull if you can run my code and tell me why the practiceBtn is not working.
the point is to get a dictionary as an input when keys are words and the values are the translation, then give the user a way to practice those words by cycling through all of them.
I have a little problem with the checkbtn value.
Here is my code:
def select_data():
select_window = Tk()
var_autotrader = IntVar()
check_sites_autotrader = Checkbutton(select_window, text = 'autotrader', variable = var_autotrader)
var_bestcarfinder = IntVar()
var_cardady = IntVar()
var_cars = IntVar()
var_car_gurus = IntVar()
var_iseecars = IntVar()
var_truecar = IntVar()
check_sites_bestcarfinder = Checkbutton(select_window, text = 'bestcarfinder', variable = var_bestcarfinder)
check_sites_cardaddy = Checkbutton(select_window, text = 'cardady', variable = var_cardady)
check_sites_cars = Checkbutton(select_window, text = 'cars.com', variable = var_cars)
check_sites_car_gurus = Checkbutton(select_window, text = 'car gurus', variable = var_car_gurus)
check_sites_iseecars = Checkbutton(select_window, text = 'iseecars', variable = var_iseecars)
check_sites_truecar = Checkbutton(select_window, text = 'truecar', variable = var_truecar)
check_sites_autotrader.grid(row = 0, column = 0, sticky = W)
check_sites_bestcarfinder.grid(row = 1, column = 0, sticky = W)
check_sites_cardaddy.grid(row = 2, column = 0, sticky = W)
check_sites_cars.grid(row = 3, column = 0, sticky = W)
check_sites_car_gurus.grid(row = 4, column = 0, sticky = W)
check_sites_iseecars.grid(row = 5, column = 0, sticky = W)
check_sites_truecar.grid(row = 6, column = 0, sticky = W)
def upload_selected_data():
print(var_autotrader.get())// This one does not give me 1 when check is on
btn = Button(select_window, text = 'go!', command = upload_selected_data)
btn.grid(row = 7, column = 0, sticky = W+E)
The trouble is that my variable is not changing when I check the box
Thank you very much!
Probably you created your "main window" with Tk(). In this case you should create another window with the Toplevel() (Not with Tk()).
It means in your case you should change the select_window = Tk() line to select_window = Toplevel()
I have to make a code that will produce a GUI that shows test results for three classes and all the information will be on a file. I have tried to do the code I can make the GUI and radio buttons and that all works, but get a button that allows you to put what ever is in the text box to be in alphabetical order.
from tkinter import *
root = Tk()
root.title("Test scores")
root.geometry("500x300")
app = Frame(root)
app.grid()
test1 = open("names.txt","r")
test2 = open("score.txt","r")
test3 = open("class.txt","r")
class Application(Frame):
def __init__(self, master):
super(Application, self).__init__(master)
self.grid()
self.create_widgets()
def create_widgets(self):
Label(self,
text = "Which class "
).grid(row = 0,column = 0, sticky = W)
Label(self,
text = "Select a class"
).grid(row = 1, column = 0, sticky = W)
self.choose = StringVar()
self.choose.set(None)
Radiobutton(self,
text = "Class 1",
variable = self.choose,
value = test1.read(),
command = self.update_text
).grid(row = 2, column = 0, sticky = W)
self.second = BooleanVar()
Radiobutton(self,
text = "Class 2",
variable = self.choose,
value = test2.read(),
command = self.update_text
).grid(row = 3, column = 0, sticky = W)
self.third = BooleanVar()
Radiobutton(self,
text = "Class 3",
variable = self.choose,
value = test3.read(),
command = self.update_text
).grid(row = 4, column = 0, sticky = W)
self.bttn = Button(self)
self.bttn["text"] = "Alphabetical"
self.bttn["command"] = self.update_order
self.bttn.grid(row = 4, column = 1, sticky = W)
self.results_txt = Text(self, width = 40, height = 5, wrap = WORD)
self.results_txt.grid(row = 5, column = 0, columnspan = 3)
def update_text(self):
likes = ""
likes += self.choose.get()
self.results_txt.delete(0.0, END)
self.results_txt.insert(0.0, likes)
def update_order(self):
sortfile = open("sorted1.txt","w")
for line in sorted(self.results_txt, key = str.lower):
sortfile.write(line)
app = Application(root)
root.mainloop()
this is my code so far.
i tried to sort it but it doesn't work this is the code i tried as i looked online and saw this
def update_order(self):
str(sorted(self.results_txt, key=lambda student: student[2]))
how would i sort file lines
so if the first line had "name" "first score" "second score" "third score"
then on the second line "different name" "first score" "second score" "third score"
how would you sort it alphabetically by the name in the line nothing else. would i need to put each score on different files?
In the code below I have managed to partially validate the data entered into the self.e2 entry widget, unfortunately if the entry widget is empty and the Submit button is pressed then a ValueError is generated" ValueError: invalid literal for int() with base 10: '' "
I would like to have the program recognise that the e2 entry widget is empty, have the ValueError trapped and return focus back to the entry widget.
I have attempted to do this using the is_valid_int and invalid_int methods but this is not working.
from tkinter import *
from tkinter import ttk
from tkinter.scrolledtext import *
class DailyOrderGUI:
def __init__(self, parent):
#Data entring frame
self.frame = Frame(parent, bg = "grey")
self.frame.grid(row=0)
self.label1 = Label(self.frame, text = "Mrs CackleBerry's Egg Ordering System", wraplength = 200, bg="grey", font=("Comic Sans MS", "14", "bold"))
self.label1.grid(row = 0, columnspan = 3, padx = 5, pady = 5)
self.superegg_img = PhotoImage(file = "images/superegg.gif")
self.label5 = Label(self.frame, bg="grey", image = self.superegg_img)
self.label5.grid(row = 0, column= 3, padx = 5, pady = 5)
self.v = StringVar()
self.v.set("Monday")
self.label2 = Label(self.frame, text = "Which day are you ordering for?", bg="grey", font=("Arial", "12", "bold"))
self.label2.grid(row = 1, columnspan = 4, sticky = W)
self.rb1 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Monday", text = "Monday")
self.rb1.grid(row = 2, column = 0, sticky = W)
self.rb2 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Tuesday", text = "Tuesday")
self.rb2.grid(row = 2, column = 1, sticky = W)
self.rb3 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Wednesday", text = "Wednesday")
self.rb3.grid(row = 2, column = 2, sticky = W)
self.rb4 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Thursday", text = "Thursday")
self.rb4.grid(row = 2, column = 3, sticky = W)
self.rb5 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Friday", text = "Friday")
self.rb5.grid(row = 3, column = 0, sticky = W)
self.rb6 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Saturday", text = "Saturday")
self.rb6.grid(row = 3, column = 1, sticky = W)
self.rb7 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Sunday", text = "Sunday")
self.rb7.grid(row = 3, column = 2, sticky = W)
self.label3 = Label(self.frame, text = "Customer's Name:?(Press \"Orders Complete\" to finish)", bg="grey", font=("Arial", "12", "bold"))
self.label3.grid(row = 4, columnspan = 4,padx = 5, sticky = W)
self.e1 = Entry(self.frame, width = 30)
self.e1.grid(row = 5, columnspan = 4, sticky = W, padx = 5, pady=3)
self.e1.focus()
self.label4 = Label(self.frame, text = "How many eggs being ordered:?", bg="grey", font=("Arial", "12", "bold"))
self.label4.grid(row = 6, columnspan = 4,padx = 5,sticky = W)
integer = self.create_integer_widget()
self.btn1 = Button(self.frame, text = "Submit")
self.btn1.grid(row = 8, padx = 5, pady = 3, sticky = E+W)
self.btn1.bind("<Button-1>", self.get_orders)
self.btn2 = Button(self.frame, text = "Orders Complete", command = self.show_summary_result)
self.btn2.grid(row = 8, column = 3, padx = 5, pady = 3, sticky = E+W)
#Summary Frame
self.summ_frame = Frame(parent, bg = "grey")
self.summ_frame.grid(row=0)
self.summ_label1 = Label(self.summ_frame, text = "Mrs CackleBerry's Egg Ordering System", bg="grey", font=("Comic Sans MS", "14", "bold"))
self.summ_label1.grid(row = 0, columnspan = 4, padx = 5, pady = 5)
self.scrolled_display = ScrolledText(self.summ_frame, width = 50, height = 10, bg="thistle", font=("Times New Roman", "12"))
self.scrolled_display.grid(row = 1, columnspan = 2, padx = 5, pady = 20, sticky = W)
self.data_entry_btn = Button(self.summ_frame, text = "Back to Data Entry", command = self.show_data_entry_frame)
self.data_entry_btn.grid(row = 2, column = 0, sticky = SE, padx = 5, pady = 20)
self.egg_orders=[]
self.show_data_entry_frame()
def create_integer_widget(self):
self.e2 = ttk.Entry(self.frame, width = 10, validate='key')
self.e2['validatecommand'] = (self.frame.register(self.is_valid_int), '%P')
self.e2['invalidcommand'] = (self.frame.register(self.invalid_int), '%W')
self.e2.grid(row = 7, columnspan = 4, sticky = W, padx = 5, pady=3)
self.e2.bind("<Return>", self.get_orders)
return self.e2
def is_valid_int(self, txt):
# txt - value in %P
if not txt: # do not accept empty string
return False
try:
int(txt)
return True # accept integer
except ValueError: # not an integer
return False
def invalid_int(self, widgetName):
# called automatically when the
# validation command returns 'False'
# get entry widget
widget = self.frame.nametowidget(widgetName)
# clear entry
widget.delete(0, END)
# return focus to integer entry
widget.focus_set()
widget.bell()
def show_data_entry_frame(self):
self.summ_frame.grid_remove()
self.frame.grid()
root.update_idletasks()
def show_summary_result(self):
self.frame.grid_remove()
self.summ_frame.grid()
root.update_idletasks()
self.scrolled_display.delete('1.0', END)
if len(self.egg_orders) == 0:
self.scrolled_display.insert(END, "No Orders")
else:
total = 0
self.scrolled_display.insert(END, "Orders for " + self.v.get() + "\n")
for i in range(len(self.egg_orders)):
total += self.egg_orders[i].num_eggs
self.scrolled_display.insert(END, str(self.egg_orders[i]) + "\n")
self.scrolled_display.insert(END, "" + "\n")
self.scrolled_display.insert(END, "Summary for " + self.v.get() + "\n")
self.scrolled_display.insert(END, "" + "\n")
self.scrolled_display.insert(END, "Total eggs: " + str(total) + "\n")
self.scrolled_display.insert(END, "Dozens required: " + str(self.get_dozens(total)) + "\n")
average = 0
if len(self.egg_orders) > 0:
average = total / len(self.egg_orders)
self.scrolled_display.insert(END, "Average number of eggs per customer: {0:.1f}".format(average) + "\n")
def get_orders(self, event):
"""
Collects order information - name, number of eggs in a loop
"""
self.name = self.e1.get()
self.no_eggs = self.e2.get()
self.e1.delete(0, END)
self.e2.delete(0, END)
self.e1.focus()
self.egg_orders.append(EggOrder(self.name, self.no_eggs))
def get_dozens (self, total):
"""
returns whole number of dozens required to meet required number of eggs
"""
num_dozens = total//12
if total%12 != 0:
num_dozens += 1
return num_dozens
class EggOrder:
price_per_doz = 6.5
def __init__(self, name, num_eggs):
self.name = name
self.num_eggs = int(num_eggs)
def calc_price(self):
self.price = EggOrder.price_per_doz/12 * self.num_eggs
return self.price
def __str__(self):
return("{} ordered {} eggs. The price is ${:.2f}".format(self.name, self.num_eggs , self.calc_price()))
#main routine
if __name__== "__main__":
root = Tk()
root.title("Mrs Cackleberry's Egg Ordering Program")
frames = DailyOrderGUI(root)
root.mainloop()
Let's trace through what happens when you click "Submit".
First:
self.btn1 = Button(self.frame, text = "Submit")
self.btn1.grid(row = 8, padx = 5, pady = 3, sticky = E+W)
self.btn1.bind("<Button-1>", self.get_orders)
So, it calls self.get_orders. And the last line in that function is:
self.no_eggs = self.e2.get()
# ...
self.egg_orders.append(EggOrder(self.name, self.no_eggs))
And inside the EggOrder.__init__ function you've got this:
self.num_eggs = int(num_eggs)
That's presumably where the error happens.
(Note that all of that work would have been unnecessary if you'd posted the traceback instead of just the error string.)
So, when self.e2.get() returns an empty string, you end up calling int(''), and that raises a ValueError.
Unless you want to try to check for that possibility in advance (which is rarely a good idea), you will need a try:/except ValueError: somewhere. The question is, where? Well, that depends on what you want to do.
If you want to create an empty EggOrder, you'd do it inside EggOrder.__init__:
try:
self.num_eggs = int(num_eggs)
except ValueError:
self.num_eggs = 0
On the other hand, if you want to not create an EggOrder at all, you'd do it inside self.get_orders:
try:
order = EggOrder(self.name, self.no_eggs)
except ValueError:
# pop up an error message, log something, call self.invalid_int, whatever
else:
self.egg_orders.append(order)
Of course you probably want to do this before all the destructive stuff (self.e1.delete(0, END), etc.).
Also, if you wanted to call invalid_int as-is, you'd need to pass it the name of the self.e2 widget. Since you didn't give it one, it'll be something dynamic and unpredictable like .1234567890, which you'll have to ask the widget for, just so you can look the widget back up by that name. It would be simpler to factor out the core functionality, something like this:
def invalid_int(self, widgetName):
widget = self.frame.nametowidget(widgetName)
self.handle_invalid_int(widget)
def handle_invalid_int(self, widget):
widget.delete(0, END)
# etc.
Then you can just call handle_invalid_int(self.e2).
Meanwhile, you've tried adding a validation function to check for a valid int input.
is_valid_int should work fine. However, the if not txt part is completely unnecessary—int(txt) will already handle an empty string the same way it handles a non-numeric string.
And the way you've hooked it up should work too.
However, a validation function runs on each edit to the Entry widget, not when you click some other random widget elsewhere. For example, if you try typing letters into the Entry, it should erase them as soon as you can type them. (Note that if you type 123a456 you'll end up with 456, not 123456, which may or may not be what you want…)
So, you've done that right, but it's not what you wanted to do.