currently working on an F1 Tkinter Gui app, which lets users input a driver (either via typing or picking a driver from a Listbox) and relevant statistics get shown.
Currently, I'm trying to do a case as follows: when the user-input doesn't match the entries in drivers_list
, the Listbox, menu
, should show 1 string of "No Item Found" (or even better, the current user_input + "Not Found")
I've tried a couple of different ways. For example, in the code shown below, I put a separate else-statement within check
, where it prints out "No Item Found", but what happens is that instead of only 1 "No Item Found" being shown in menu
, multiple get shown. I think I know why multiple get shown, but I don't know a solution to fix it. It does seem that the issue lies within check
, but I could be wrong
Here's the code:
#UI Design approach 4
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)
else:
data.append("Item not Found")
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.configure(text = team)
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.configure(text = code)
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.configure(text = nationality)
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.configure(text = wins)
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.configure(text = poles)
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.configure(text = podiums)
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.configure(text = championships)
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.configure(text = standing)
def grab_user_input():
#need to find a scalable way, since what if this was an app to search any driver in history?
edge_case_inputs = ["Max Verstappen", "Kevin Magnussen", "Mick Schumacher"]
user_input = entry_box.get()
if user_input in edge_case_inputs:
lower_user_input = user_input.lower().replace(" ", "_")
return lower_user_input
#very unique case which can't be modularsed
elif user_input == "Nyck de Vries":
lower_user_input = "de_vries"
else:
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
hide_button(menu)
#fast-run time
full_name()
#fast-run time
team()
#fast-run time
driver_code()
#fast-run time
nationality()
#fast-run time
wins()
#fast-run time
poles()
#fast-run time
podiums()
#fast-run time
championships()
#fast-run time
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)
#pass something into the lamda
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 = "", 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)
team_api = Label(main_frame, text = "", font = ("Arial", 10))
team_api.grid(row = 1, column = 1)
nationality_label = Label(main_frame, text = "NATIONALITY", font = ("Arial", 10))
nationality_label.grid(row = 2, column = 0, sticky = W)
nationality_api = Label(main_frame, text = "", font = ("Arial", 10))
nationality_api.grid(row = 2, column = 1, sticky = W)
driver_code_label = Label(main_frame, text = "DRIVER CODE", font = ("Arial", 10))
driver_code_label.grid(row = 3, column = 0, sticky = W)
code_api = Label(main_frame, text = "", font = ("Arial", 10))
code_api.grid(row = 3, column = 1, sticky = W)
wins_label = Label(main_frame, text = "WINS", font = ("Arial", 10))
wins_label.grid(row = 4, column = 0, sticky = W)
wins_api = Label(main_frame, text = "", font = ("Arial", 10))
wins_api.grid(row = 4, column = 1, sticky = W)
podiums_label = Label(main_frame, text = "PODIUMS", font = ("Arial", 10))
podiums_label.grid(row = 1, column = 2, sticky = W, padx = 15)
podiums_api = Label(main_frame, text = "", font = ("Arial", 10))
podiums_api.grid(row = 1, column = 3, padx = 15, sticky = W)
poles_label = Label(main_frame, text = "POLES", font = ("Arial", 10))
poles_label.grid(row = 2, column = 2, sticky = W, padx = 15)
poles_api = Label(main_frame, text = "", font = ("Arial", 10))
poles_api.grid(row = 2, column = 3, 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)
championships_api = Label(main_frame, text = "", font = ("Arial", 10))
championships_api.grid(row = 3, column = 3, 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)
standing_api = Label(main_frame, text = "", font = ("Arial", 10))
standing_api.grid(row = 4, column = 3, padx = 15, sticky = W)
hide_button(menu)
hide_button(main_frame)
root.mainloop()
If anyone has follow-up questions for clarity, let me know!
Thanks, Safwan