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
Instead of adding "Item not found" to data
in every iteration of the loop, don't add it until after the loop, if data
is empty.
if v.lower() in item.lower():
data.append(item)
# no else part
if not data: # data is empty
data.append("Item not found")