diff --git a/app.py b/app.py index d7851cd..a12103a 100644 --- a/app.py +++ b/app.py @@ -1,15 +1,18 @@ import tkinter as tk +from tkinter import ttk import requests import io -from Essential.prepare_db import prepare_db from PIL import Image, ImageTk +from Essential.prepare_db import prepare_db from Essential.FoodSearch import FoodSearch - +import threading class App: def __init__(self, master): self.master = master + # Search food from database ----------------- + try: self.food_search = FoodSearch() except FileNotFoundError: @@ -19,39 +22,65 @@ class App: self.search_var = tk.StringVar() self.search_var.trace('w', self.search_callback) - self.search_entry = tk.Entry(self.master, textvariable=self.search_var) - self.search_entry.grid(row=0, column=0, padx=10, pady=10) + self.search_entry = ttk.Entry(self.master, textvariable=self.search_var) + self.search_entry.grid(row=0, column=0, padx=10, pady=10, sticky="nsew") - self.search_button = tk.Button(self.master, text="Search", command=self.search) - self.search_button.grid(row=1, column=0, padx=10, pady=10) + self.search_button = ttk.Button(self.master, text="Search", command=self.start_search) + self.search_button.grid(row=0, column=1, padx=10, pady=10, sticky="nsew") - self.results_frame = tk.Frame(self.master) - self.results_frame.grid(row=2, column=0, padx=10, pady=10, sticky="nsew") + self.results_frame = ttk.Frame(self.master) + self.results_frame.grid(row=1, column=0, padx=10, pady=10, sticky="nsew") - self.scrollbar = tk.Scrollbar(self.results_frame) - self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) + self.scrollbar = ttk.Scrollbar(self.results_frame) + self.scrollbar.grid(row=0, column=2, sticky="ns") self.results_listbox = tk.Listbox(self.results_frame, yscrollcommand=self.scrollbar.set) - self.results_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + self.results_listbox.grid(row=0, column=0, columnspan=2, sticky="nsew") self.scrollbar.config(command=self.results_listbox.yview) self.selected_item = None - self.image_frame = tk.Frame(self.master, bg='white') - self.image_frame.grid(row=0, column=2, rowspan=3, padx=10, pady=10, sticky="nsew") + # Image of food ----------------- + + self.image_frame = ttk.Frame(self.master, borderwidth=2, relief=tk.SUNKEN) + self.image_frame.grid(row=2, column=0, padx=10, pady=10, sticky="nsew", columnspan=2) + self.image_frame.grid_rowconfigure(0, weight=1) + self.image_frame.grid_columnconfigure(0, weight=1) + + # Progress bar ----------------- + + self.progress_bar = ttk.Progressbar(self.master, mode='indeterminate') + self.progress_bar.grid(row=3, column=0, columnspan=2, padx=10, pady=10, sticky="we") + + # Default image (Not Found) ----------------- + + self.default_image_path = 'resources/notfound.png' # Replace with the correct path to your default image + self.default_image = ImageTk.PhotoImage(Image.open(self.default_image_path)) + self.default_image_label = ttk.Label(self.image_frame, image=self.default_image) + self.default_image_label.grid(row=0, column=0, padx=10, pady=10, sticky="nsew") self.master.columnconfigure(0, weight=1) self.master.columnconfigure(1, weight=0) - self.master.columnconfigure(2, weight=1) + self.master.rowconfigure(1, weight=1) self.master.rowconfigure(2, weight=1) + # Configure the window size and position + self.master.geometry("800x600") + # self.master.attributes('-fullscreen', True) + def search_callback(self, *args): pass + def start_search(self): + # Create a new thread to execute the search function + search_thread = threading.Thread(target=self.search) + search_thread.start() + def search(self): results = self.food_search.search(self.search_var.get()) - self.update_results(results) + # Call the update_results function on the main thread to update the GUI + self.master.after(0, self.update_results, results) def update_results(self, results): self.results_listbox.delete(0, tk.END) @@ -70,6 +99,8 @@ class App: self.selected_item = value self.show_image(self.selected_item) + # Image Showing Section ----------------- + def show_image(self, item): image_url = None for result in self.food_search.search(self.search_var.get()): @@ -78,25 +109,49 @@ class App: break if not image_url: + self.display_default_image() return + threading.Thread(target=self.fetch_and_display_image, args=(image_url,)).start() + + def fetch_and_display_image(self, image_url): + self.master.after(0, self.show_progress_bar) + + # Fetch the image response = requests.get(image_url) img_data = response.content img = Image.open(io.BytesIO(img_data)) img = img.resize((300, 300), Image.ANTIALIAS) img_tk = ImageTk.PhotoImage(img) - # remove old image label widget + self.master.after(0, self.hide_progress_bar) + + self.master.after(0, self.update_image_label, img_tk) + + def show_progress_bar(self): + self.progress_bar.start() + self.progress_bar.grid(row=3, column=1) + + def hide_progress_bar(self): + self.progress_bar.stop() + self.progress_bar.pack_forget() + + def display_default_image(self): + self.master.after(0, self.update_image_label, self.default_image) + + def update_image_label(self, image): + # Remove old image label widget for widget in self.image_frame.winfo_children(): widget.destroy() - self.image_frame.configure(bg='white') - label = tk.Label(self.image_frame, image=img_tk, bg='white') - label.image = img_tk - label.pack(fill=tk.BOTH, expand=True) + image_label = tk.Label(self.image_frame, image=image) + image_label.image = image + image_label.grid(row=0, column=2) + + # --------------------- + root = tk.Tk() app = App(root) -root.geometry("800x400") root.title('Food Search') app.results_listbox.bind('<>', app.on_item_selected) diff --git a/resources/loading.gif b/resources/loading.gif new file mode 100644 index 0000000..b3302ca Binary files /dev/null and b/resources/loading.gif differ diff --git a/resources/notfound.png b/resources/notfound.png new file mode 100644 index 0000000..0e60948 Binary files /dev/null and b/resources/notfound.png differ