Just finished my cookbook project using tkinter.
I have it connected to a public database. Unfortunately I do not have fiber optic so my upload speed is slow. If you do not want to wait the few seconds for the queries, there is only one table with the required fields. I was using the database created by django. Any how the fields needed in the table are: id, title, prep_time, cook_time, ingredients, and .directions.
Constructive criticism welcome.
I have it connected to a public database. Unfortunately I do not have fiber optic so my upload speed is slow. If you do not want to wait the few seconds for the queries, there is only one table with the required fields. I was using the database created by django. Any how the fields needed in the table are: id, title, prep_time, cook_time, ingredients, and .directions.
Constructive criticism welcome.
#! /usr/bin/env python3.8 ### Do imports ### import tkinter as tk from tkinter import ttk from tkinter import messagebox from PIL import Image, ImageTk import string from functools import partial import pymysql import webbrowser ### Database class for connecting and querying our database class Database(): ### Define some global vars HOST = 'recipes.phpshelf.net' USER = 'public' PASSWD = 'public' DB = 'public' PORT = 3306 ### Initiate our connection def __init__(self): try: self.conn = pymysql.connect(self.HOST, self.USER, self.PASSWD, self.DB, self.PORT) except pymysql.OperationalError as e: if e: print('Error: Please check your database connection settings') msg = messagebox.showerror(title = 'Database Connection', message = 'Error! Please check database connection settings.') quit() ### Query the database for our titles def TitleQuery(self,letter): try: query = f'select id, title from homepages_post where title like "{letter}%"' with self.conn.cursor() as cursor: cursor.execute(query) results = cursor.fetchall() return results except pymysql.InternalError as e: print('Database Error! Please check your database query for errors.') msg = messagebox.showerror(title = 'Database Error', message = 'Error! Please check query format settings.') quit() ### Query the database for recipes def IDQuery(self, id): try: query = f'select * from homepages_post where id = "{id}"' with self.conn.cursor() as cursor: cursor.execute(query) results = cursor.fetchall() return results except pymysql.InternalError as e: msg = messagebox.showerror(title = 'Database Error', message = 'Error! Please check query format settings.') quit() ### Our main window class class MainWindow(ttk.Frame): def __init__(self, master): self.master = master self.master.grid_columnconfigure(0, weight = 1) self.master.grid_rowconfigure(0, weight = 1) ### Get the screen width and height self.screenwidth = master.winfo_screenwidth() self.screenheight = master.winfo_screenheight() ### MainFrame holds all other grids and widgets self.MainFrame = ttk.Frame(self.master) self.MainFrame.grid(column = 0, row = 0, sticky = ('new')) self.MainFrame.grid_columnconfigure(0, weight = 1) self.MainFrame.grid_rowconfigure(0, weight = 1) ########### Main container frames start ############################################################ ### This frame grid will hold the logo panel ### Parent MainFrame self.Logo_Frame = ttk.Frame(self.MainFrame) self.Logo_Frame.grid(column = 0, row = 0, sticky = 'new') self.Logo_Frame.grid_columnconfigure(0, weight = 3) ### This frame grid will the letter menu ### Parent MainFrame self.Letter_Menu_Frame = ttk.Frame(self.MainFrame, relief = 'raised', padding = 5) self.Letter_Menu_Frame.grid(column = 0, row = 1, sticky = 'new') for i in range(26): self.Letter_Menu_Frame.grid_columnconfigure(i, weight = 3) ### This frame grid will hold two subframe/canvas grids ### Parent MainFrame self.MultiGrid_Frame = ttk.Frame(self.MainFrame) self.MultiGrid_Frame.grid(column = 0, row = 2, sticky = 'nw') self.MultiGrid_Frame.grid_columnconfigure(0, weight = 3) ### This frame grid will hold the footer widget ### Parent MainFrame fstyle = ttk.Style() fstyle.configure('F.TFrame', relief = 'raised', padd = 8) self.Footer_Frame = ttk.Frame(self.MainFrame, style = 'f.TFrame') self.Footer_Frame.grid(column = 0, row = 3, sticky = 'new') self.Footer_Frame.grid_columnconfigure(0, weight = 3) ########## Main container frames end ############################################################### ### This subframe will hold a canvas for scrolling and a recipe title list ### Parent MultiGrid_Frame self.Menu_Title_Frame = ttk.Frame(self.MultiGrid_Frame, padding = 8, border = 3, relief = 'ridge') self.Menu_Title_Frame.grid(column = 0, row = 0, sticky = 'nsw') self.Menu_Title_Frame.grid_columnconfigure(0, weight = 3) self.Menu_Title_Frame.grid_rowconfigure(0, weight = 3) ### This subframe will hold a canvas for scrolling and recipe display ### Parent MultiGrid_Frame self.GetRecipe_Frame = ttk.Frame(self.MultiGrid_Frame, padding = 8, border = 3, relief = 'ridge') self.GetRecipe_Frame.grid(column = 1, row = 0, sticky = 'nsw') self.GetRecipe_Frame.grid_columnconfigure(0, weight = 3) self.GetRecipe_Frame.grid_rowconfigure(0, weight = 3) ### Start Init Methods/Functions ########################################################## self.Logo() self.LetterMenu() self.TitleMenu() self.GetRecipe(id = 1) self.Footer() ### End Method/Function Init ############################################################## def Footer(self): style = ttk.Style() style.map('Footer.TLabel') style.configure('Footer.TLabel', foreground = 'blue', font = ('Sans', 9, 'normal'), padding = 8, border = 2) footer = ttk.Button(self.Footer_Frame, text = 'Register @ Johnny\'s CookBook', style = 'Footer.TLabel', cursor = 'hand2', command = self.Web) footer.grid(column = 0, row = 0, sticky = 'n') footer.grid_columnconfigure(0, weight = 3) ### Method for opening a webbrowser def Web(self): webbrowser.open_new('http://recipes.phpshelf.net') ### Function/Method for displaying the recipe def GetRecipe(self, id): canvas = tk.Canvas(self.GetRecipe_Frame, width = 600) canvas.configure(border = 5, highlightcolor = 'gray87') scrollbar = ttk.Scrollbar(self.GetRecipe_Frame, orient = 'vertical', command = canvas.yview) scrollable_frame = ttk.Frame(canvas) scrollable_frame.bind( '<Configure>', lambda e: canvas.configure(scrollregion = canvas.bbox('all')) ) canvas.create_window((0, 0), window = scrollable_frame, anchor = 'nw') canvas.configure(yscrollcommand = scrollbar.set) data = Database().IDQuery(id = id) style = ttk.Style() ### Title style.configure('Title.TLabel', font = ('Sans', 12, 'bold', 'underline'), foreground = 'blue', padding = 5, relief = 'raised') title = ttk.Label(scrollable_frame, text = f' {data[0][1]}', style = 'Title.TLabel') title.grid(columnspan = 2, column = 0, row = 0, sticky = 'new') ### Prep/Cook/Total Times prep = self.TimeConvert(data[0][5]) cook = self.TimeConvert(data[0][6]) total = self.TimeConvert(data[0][5] + data[0][6]) style2 = ttk.Style() style2.configure('Time.TLabel', foreground = 'blue', relief = 'raised', padding = 5) times = ttk.Label(scrollable_frame, text = f' Prep Time: {prep} | Cook Time: {cook} | Total Time: {total}' , style = 'Time.TLabel') times.grid(columnspan = 2, column = 0, row = 1, sticky = 'new') ### Mini Headers for ingredients and instructions style3 = ttk.Style() style3.configure('MiniHeader.TLabel', font = ('Sans', 10, 'bold','underline', 'italic') ,foreground = 'blue', relief = 'raised', padding = 5) mini_header1 = ttk.Label(scrollable_frame, text = ' Ingredients', style = 'MiniHeader.TLabel') mini_header1.grid(column = 0, row = 2, sticky = 'new') mini_header2 = ttk.Label(scrollable_frame, text = ' Instructions', style = 'MiniHeader.TLabel') mini_header2.grid(column = 1, row = 2, sticky = 'new') style4 = ttk.Style() style4.configure('Recipe.TLabel', padding = 8, border = 8, relief = 'sunken', wraplength = 300) ingredients = ttk.Label(scrollable_frame, text = data[0][2], style = 'Recipe.TLabel') ingredients.grid(column = 0, row = 3, sticky = 'nw') instructions = ttk.Label(scrollable_frame, text = data[0][3], style = 'Recipe.TLabel') instructions.grid(column = 1, row = 3, sticky = 'nw') scrollbar.grid(column = 0, row = 0, sticky = 'nsw') canvas.grid(column = 1, row = 0, sticky = 'nsw') ### Convert Times def TimeConvert(self, nums): h, m = divmod(nums, 60) hours = 'hr' if nums > 60: if h > 1: hours = 'hrs' if m > 0: rtime = f'{h} {hours} {m} min.' else: rtime = f'{h} {hours}' else: rtime = f'{nums} min.' return rtime ### Function/Method for getting all recipe titles def TitleMenu(self, letter = 'a'): canvas = tk.Canvas(self.Menu_Title_Frame) canvas.configure(border = 5, highlightcolor = 'gray87') scrollbar = ttk.Scrollbar(self.Menu_Title_Frame, orient = 'vertical', command = canvas.yview) scrollable_frame = ttk.Frame(canvas) scrollable_frame.bind( '<Configure>', lambda e: canvas.configure(scrollregion = canvas.bbox('all')) ) canvas.create_window((0, 0), window = scrollable_frame, anchor = 'nw') canvas.configure(yscrollcommand = scrollbar.set) data = Database().TitleQuery(letter = letter) if len(data) > 0: self.old_letter = letter if len(data) == 0: msg = messagebox.showerror(title = 'No listing', message = 'Sorry, there have not been any recipes added starting with ' + letter) if msg == 'ok': self.TitleMenu(self.old_letter) style = ttk.Style() style.map('L.TLabel', background = [('pressed', '!disabled', 'gray86'),('active','#ffffee')], foreground = [('pressed', 'red'),('active', 'red')] ) style.configure('L.TLabel', relief = 'flat', padding = 2, foreground = 'blue') for id, title in data: title = ttk.Button(scrollable_frame, text = title.title(), style = 'L.TLabel', cursor = 'hand2', command = partial(self.GetRecipe, id)) title.grid(column = 0, row = id, sticky = 'nw') scrollbar.grid(column = 0, row = 0, sticky = 'nsw') canvas.grid(column = 1, row = 0, sticky = 'nsw') ### Function/Method for getting logo image and displaying def Logo(self): # self.imgfile = tk.PhotoImage(file = '/home/johnny/Desktop/play/cookbook_logo.png') # logo = ttk.Label(self.Logo_Frame, image = self.imgfile, anchor = 'n') style = ttk.Style() style.configure('Logo.TLabel', foreground = 'blue2', font = ('Sans', 16, 'bold'), padding = 8, border = 5) logo = ttk.Label(self.Logo_Frame, text = 'Johnny\'s CookBook', anchor = 'n', style = 'Logo.TLabel') logo.grid(column = 0, row = 0, sticky = 'new') ### Function/Method for displaying the letter menu def LetterMenu(self): letters = string.ascii_uppercase i = 0 for letter in letters: button_style = ttk.Style() button_style.configure('Button.TButton') button = ttk.Button(self.Letter_Menu_Frame, text = letter, width = 1, style = 'Button.TButton', command = partial(self.TitleMenu, letter)) button.grid(column = i, row = 0, sticky = 'new', padx = 2) button.grid_columnconfigure(i, weight = 3) i += 1 def main(): root = tk.Tk() root.title('Johnny\'s CookBook') imgfile = tk.PhotoImage(file = '/home/johnny/Desktop/play/cookbook_logo.png') root.configure(width = imgfile.width(), border = 5, relief = 'ridge') root.resizable(width = False, height = False) app = MainWindow(root) root.mainloop() if __name__ == '__main__': main()
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags
Download my project scripts
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags
Download my project scripts