I have created a code that takes random "cocktail of the day" from JSON. Everything works great:
- click on image refreshes data,
- click on Fav icon stores current data in sql (like an local archive),
- click on the header changes from online/local version and vice versa.
Now, data manipulation works great, but on the header I have two labels: "label_online" whick text changes from online to archive depending on source, and "Category" which shows cocktail category. They both work as they should, but the problem is they randomly disappear when I click on header. On every click they act randomly, sometimes they disappear, sometimes they don't.
import io
import json
import tkinter as tk
import urllib.request
from PIL import Image, ImageTk
from urllib.request import urlopen
import requests
import sqlite3
import datetime
now = datetime.datetime.now()
datetime_str = now.strftime("%Y%m%d%H%M%S")
id = "4d4-" + datetime_str
date_str = now.strftime("%d.%m.%Y.")
conn = sqlite3.connect('cocktails.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS cocktails_4d4 (
id TEXT PRIMARY KEY,
name_4d4 TEXT,
instructions_4d4 TEXT,
photo_path_4d4 TEXT,
ingredients_4d4 TEXT,
category_4d4 TEXT,
date_4d4 TEXT
)
''')
def do_resize(): # <-- return to original size
root.geometry('520x280')
def do_refresh():
root.geometry('520x281') # <-- temporary change window size by 1 px to avoid label disappear
root.after(5, do_resize) # <-- return it to original size
def change_title(new_title):
root.title(new_title)
def update_cocktail_image(event=None):
global id, cocktail, instructions, ingredients, category, cocktail_photo_path, date_str, datetime_str, image2
now = datetime.datetime.now()
datetime_str = now.strftime("%Y%m%d%H%M%S")
id = "4d4-" + datetime_str
date_str = now.strftime("%d.%m.%Y.")
url = 'https://www.thecocktaildb.com/api/json/v1/1/random.php'
response = urlopen(url)
data_json = json.loads(response.read())
cocktail_photo_fav1.configure(image=image_fav1)
cocktail = data_json['drinks'][0]['strDrink']
instructions = data_json['drinks'][0]['strInstructions']
cocktail_name.config(text=cocktail)
cocktail_inst.config(text=instructions)
change_title(f'Cocktail of the day - {cocktail}')
cocktail_photo_path = data_json['drinks'][0]['strDrinkThumb']
response = requests.get(cocktail_photo_path)
image_data = response.content
image2 = Image.open(io.BytesIO(image_data)).resize((120, 120))
image2 = ImageTk.PhotoImage(image2)
cocktail_photo.configure(image=image2)
cocktail_photo.image = image2
ingredients = ""
for i in range(1, 16):
ingredient = data_json['drinks'][0].get(f'strIngredient{i}')
measure = data_json['drinks'][0].get(f'strMeasure{i}')
if ingredient and measure:
ingredients += f"{measure} {ingredient}\n"
cocktail_ingredients.configure(text=ingredients)
#print(ingredients)
category=data_json['drinks'][0]['strCategory']
category_lbl.configure(text=f'Category: {category}')
#print(datetime_str)
do_refresh()
cocktail_displayed = False
def save_or_delete_cocktail(event):
if header.cget('bg') == 'darkred':
confirm_delete()
else:
save_cocktail()
def confirm_delete():
global confirm_label, confirm_button, cancel_button
confirm_label = tk.Label(footer, text="Delete?", font=('Segoe UI', 10), bg='darkgoldenrod', fg='white')
confirm_label.pack(padx=20, pady=10, side='left')
confirm_button = tk.Button(footer, text="Yes, delete it", font=('Segoe UI', 10), bg='darkgoldenrod', fg='white', command=cocktail_delete)
confirm_button.pack(padx=10,pady=10,side='left')
def cancel_deletion():
#confirm_window.destroy()
confirm_label.pack_forget()
confirm_button.pack_forget()
cancel_button.pack_forget()
confirm_button.pack_forget()
cocktail_photo_fav1.configure(image=image_fav2)
cancel_button = tk.Button(footer, text="No, cancel", font=('Segoe UI', 10), bg='darkgoldenrod', fg='white', command=cancel_deletion)
cancel_button.pack(padx=20, pady=10, side='left')
def cocktail_delete():
global id
conn = sqlite3.connect('cocktails.db')
cursor = conn.cursor()
curr_id=cocktail_id.cget('text')
#print(curr_id)
cursor.execute("DELETE FROM cocktails_4d4 WHERE id=?", (curr_id,))
conn.commit()
#print(f"Cocktail {curr_id} deleted")
previous_cocktail()
confirm_label.pack_forget()
confirm_button.pack_forget()
cancel_button.pack_forget()
confirm_button.pack_forget()
cocktail_photo_fav1.configure(image=image_fav2)
def save_cocktail():
#cocktail_id = str(uuid.uuid4())
cursor.execute('''
INSERT INTO cocktails_4d4 (id, name_4d4, instructions_4d4, photo_path_4d4, ingredients_4d4, category_4d4, date_4d4)
VALUES (?, ?, ?, ?, ?, ?, ?)
''', (id, cocktail, instructions, cocktail_photo_path, ingredients, category, date_str))
conn.commit()
#conn.close()
cocktail_photo_fav1.configure(image=image_fav2)
global cocktail_displayed
cocktail_displayed = True
print(f'cocktail {cocktail} saved')
def update_cocktail_labels(row):
global cocktail_id
cocktail_id.configure(text=row[0])
cocktail_name.configure(text=row[1])
cocktail_inst.configure(text=row[2])
#------------------------------------
cocktail_photo_path = row[3]
response = requests.get(cocktail_photo_path)
image_data = response.content
imagea = Image.open(io.BytesIO(image_data)).resize((120, 120))
imagea = ImageTk.PhotoImage(imagea)
cocktail_photo.configure(image=imagea)
cocktail_photo.image = imagea
#------------------------------------
cocktail_ingredients.configure(text=row[4])
category_lbl.configure(text=row[5])
#print(row[3])
def previous_cocktail():
global current_cocktail_index
current_cocktail_index -= 1
conn = sqlite3.connect('cocktails.db')
cursor = conn.cursor()
cursor.execute("SELECT * FROM cocktails_4d4")
rows = cursor.fetchall()
if current_cocktail_index < 0:
current_cocktail_index = len(rows) - 1
update_cocktail_labels(rows[current_cocktail_index])
def next_cocktail():
global current_cocktail_index
current_cocktail_index += 1
conn = sqlite3.connect('cocktails.db')
cursor = conn.cursor()
cursor.execute("SELECT * FROM cocktails_4d4")
rows = cursor.fetchall()
if current_cocktail_index >= len(rows):
current_cocktail_index = 0
update_cocktail_labels(rows[current_cocktail_index])
def change_header():
if header.cget('bg') == "darkgreen":
header.config(bg="darkred")
category_lbl.config(bg="darkred")
header_online.config(text='Location: | Archive |', bg='darkred')
do_refresh()
#print(header.cget('bg'))
conn = sqlite3.connect('cocktails.db')
cursor = conn.cursor()
cursor.execute("SELECT * FROM cocktails_4d4")
rows = cursor.fetchall()
global current_cocktail_index
current_cocktail_index = 0
update_cocktail_labels(rows[current_cocktail_index])
cocktail_photo_fav1.configure(image=image_fav2)
# Add the "previous" and "next" buttons
previous_button.pack(side="left", padx=5)
next_button.pack(side="right", padx=5)
footer.configure(text='')
do_refresh()
else:
header.config(bg="darkgreen")
category_lbl.config(bg="darkgreen")
header_online.config(text='Location: | Online |', bg='darkgreen')
do_refresh()
update_cocktail_image()
previous_button.pack_forget()
next_button.pack_forget()
footer.configure(text="Hit Me ")
#print(header.cget('bg'))
#############################################################################################################
url='https://www.thecocktaildb.com/api/json/v1/1/random.php'
response=urlopen(url)
data_json=json.loads(response.read())
root = tk.Tk()
#json
cocktail=data_json['drinks'][0]['strDrink']# <-- name of the random cocktail
instructions=data_json['drinks'][0]['strInstructions']
ingredients = ""
for i in range(1, 16):
ingredient = data_json['drinks'][0].get(f'strIngredient{i}')
measure = data_json['drinks'][0].get(f'strMeasure{i}')
if ingredient and measure:
ingredients += f"{measure} {ingredient}\n"
category=data_json['drinks'][0]['strCategory']
#start
root.title(f'Cocktail of the day - {cocktail}')
root.geometry('520x280')
header = tk.Label(root, text="My Cocktail of the Day ", font=("Segoe UI", 14, 'bold'), bg="darkgreen", fg="white", height=2, anchor='ne', justify='right')
header.pack(side="top", fill="x")
header.pack_propagate(False)
header.bind("<Button-1>", lambda event: change_header())
header_online=tk.Label(header, text='Location: | Online |',font=('Segoe UI', 10), bg='darkgreen', fg='white')
header_online.place(x=15, y=0)
category_lbl=tk.Label(header, text=f'Category: {category}', font=('Segoe UI', 9, "bold"), bg="darkgreen", fg='white')
category_lbl.place(x=302, y=25)
cocktail_photo_path=data_json['drinks'][0]['strDrinkThumb']
response = requests.get(cocktail_photo_path)
image_data = requests.get(cocktail_photo_path).content
image = Image.open(io.BytesIO(image_data)).resize((120, 120))
image = ImageTk.PhotoImage(image)
cocktail_photo = tk.Label(root, image=image, wraplength=100)
cocktail_photo.place(x=20, y=25)
cocktail_photo.bind('<Button-1>', update_cocktail_image)
url_fav1='https://devling.com.hr/webdisk/python/Cocktails/favorite_1.png'
response = requests.get(url_fav1)
image_data_fav1 = requests.get(url_fav1).content
image_fav1 = Image.open(io.BytesIO(image_data_fav1)).resize((20, 25))
image_fav1 = ImageTk.PhotoImage(image_fav1)
url_fav2='https://devling.com.hr/webdisk/python/Cocktails/favorite_2.png'
response = requests.get(url_fav2)
image_data_fav2 = requests.get(url_fav2).content
image_fav2 = Image.open(io.BytesIO(image_data_fav2)).resize((20, 25))
image_fav2 = ImageTk.PhotoImage(image_fav2)
cocktail_photo_fav1 = tk.Label(root, image=image_fav1)
cocktail_photo_fav1.place(x=480, y=50)
cocktail_photo_fav1.bind('<Button-1>', save_or_delete_cocktail)
cocktail_ing=tk.Label(root, text='Ingredients: ', font=('Segoe UI', 9, 'bold'), fg='dimgray')
cocktail_ing.place(x=20, y=150)
cocktail_id=tk.Label(root, text='')
cocktail_id.place(x=0, y=0)
cocktail_id.place_forget()
cocktail_ingredients = tk.Label(root, text=ingredients, font=('SegoeUI', 9), anchor='w', justify='left')
cocktail_ingredients.place(x= 20, y=170)
cocktail_name = tk.Label(root, text=cocktail, font=('SegoeUI', 12, 'bold'))
cocktail_name.place(x= 160, y=60)
cocktail_inst = tk.Label(root, text=instructions, font=('SegoeUI', 10), wraplength=350, anchor='w', justify='left')
cocktail_inst.place(x= 160, y=90)
footer = tk.Label(root, text="Hit Me ", font=("Segoe UI", 13, "bold"), bg="darkgoldenrod", fg="white", height=1, anchor='e', justify='right')
footer.pack(side="bottom", fill="x")
footer.bind('<Button-1>', update_cocktail_image)
arrow_char = "\u279c"
previous_button = tk.Button(footer, text="\u2b98", font=("Wingdings", 9, "bold"), height=1, bg="darkgoldenrod", fg="white", command=previous_cocktail)
previous_button.pack(side="left", padx=5)
previous_button.pack_forget()
next_button = tk.Button(footer, text="\u2b9a", font=("Wingdings", 9, "bold"), bg="darkgoldenrod", fg="white", command=next_cocktail)
next_button.pack(side="right", padx=5)
next_button.pack_forget()
#print(f"Moj odabrani koktel je {cocktail}")
root.mainloop()
I've noticed that when they disappear, and I move window border (even for 1px) they appear back, so only solution I could think of was to resize root.geometry by 1px and return it to original size after 5ms.
Here is the code that does that:
def do_resize(): # <-- return to original size
root.geometry('520x280')
def do_refresh():
root.geometry('520x281') # <-- temporary change window size by 1 px to avoid label disappear
root.after(5, do_resize) # <-- return it to original size
and the I call function "do_refresh" on every click on header_online, and it works. Is there a better solution, and what am I doing wrong?