This program implements an object oriented management system for a wine library. It incorprates a user friendly GUI to facilitate user interaction. A detailed documentation can be found at:
# Ex 3.3 Wine Library
####################################################
# IMPORT PACKAGES TO SUPPORT THE PROGRAM
####################################################
import csv
from tkinter import *
from tkinter import ttk
####################################################
# DEFINE THE BOTTLE CLASS
####################################################
class Bottle():
def __init__(self,bottle_id,winery,varietal,vintage,cat,comment,bin_no,irow,icol):
self.bottle_id=bottle_id
self.winery=winery
self.varietal=varietal
self.vintage=vintage
self.cat=cat
self.comment=comment
self.bin_no=bin_no
self.irow=irow
self.icol=icol
def update_bottle(self,bid):
bottles[bid].winery=bot_winery_entry.get()
bottles[bid].varietal=bot_var_entry.get()
bottles[bid].vintage=bot_vin_entry.get()
bottles[bid].cat=bot_cat_entry.get()
bottles[bid].comment=bot_com_entry.get()
bottles[bid].bin_no=bot_bin_entry.get()
bottles[bid].irow=bot_row_entry.get()
bottles[bid].icol=bot_col_entry.get()
def display_bottles(self,bottle_id):
bottle_tree.insert('', 'end', values=(bottles[bottle_id].bottle_id,
bottles[bottle_id].winery,
bottles[bottle_id].varietal,
bottles[bottle_id].vintage,
bottles[bottle_id].cat,
bottles[bottle_id].comment,
bottles[bottle_id].bin_no,
bottles[bottle_id].irow,
bottles[bottle_id].icol))
####################################################
# INSTANTIATE BOTTLE OBJECTS FROM Wine-data.csv
####################################################
bottles=[] # holds the bottle objects; the index is the bottle number
nbottles=0 # number of bottles in cellar
varietal_list=["Select Varietal"]
cat_list=["select category","all"]
winery_list=["Select Winery"]
rack_list=["select rack"]
with open('Data/Wine-data.csv') as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
line_count = 0
for row in csv_reader:
if line_count == 0:
line_count += 1
else:
bottle_id=int(row[0])
winery=row[1]
varietal=row[2]
vintage=row[3]
cat=row[4]
comment=row[5]
bin_no=int(row[6])
irow=int(row[7])
icol=int(row[8])
new_bottle=Bottle(bottle_id,winery,varietal,vintage,cat,comment,bin_no,irow,icol)
bottles.append(new_bottle)
if(winery not in winery_list):winery_list.append(winery)
if(cat not in cat_list):cat_list.append(cat)
if(varietal not in varietal_list):varietal_list.append(varietal)
if(bin_no not in rack_list):rack_list.append(bin_no)
nbottles+=1
####################################################
# CREATE THE GUI INTERFACE
####################################################
root = Tk()
root.geometry("1000x800")
select_cat = StringVar(root)
select_var = StringVar(root)
select_winery = StringVar(root)
select_rack = StringVar(root)
####################################################
# SELECT FRAME
####################################################
#-----Define functions used in Select Frame
def update_cat(event):
global select_cat
#Clear the treeview list items
for item in bottle_tree.get_children():
bottle_tree.delete(item)
select=str(select_cat.get())
for iid in range(nbottles):
if(select=="all") :
bottles[iid].display_bottles(iid)
else:
if(bottles[iid].cat==select and bottles[iid].bin_no != 0) :
bottles[iid].display_bottles(iid)
def update_var(event):
global select_var
#Clear the treeview list items
for item in bottle_tree.get_children():
bottle_tree.delete(item)
select=str(select_var.get())
for iid in range(nbottles):
if(bottles[iid].varietal==select and bottles[iid].bin_no != 0):
bottles[iid].display_bottles(iid)
def update_winery(event):
global select_winery
#Clear the treeview list items
for item in bottle_tree.get_children():
bottle_tree.delete(item)
select=str(select_winery.get())
for iid in range(nbottles):
if(bottles[iid].winery==select and bottles[iid].bin_no != 0): bottles[iid].display_bottles(iid)
def update_rack(event):
global select_rack
Nrows=[1,6,4,3]
Ncols=[100,9,2,6]
#Clear the treeview list items
for item in bottle_tree.get_children():
bottle_tree.delete(item)
select=str(select_rack.get())
for iid in range(nbottles): bottles[iid].display_bottles(iid)
if(select!="0"):
iselect=int(select)
rack = Tk()
rack.geometry("1600x1800+100+100")
rack.title("Rack"+ select)
rack.configure(background='burlywood4')
textvar=StringVar(rack)
textvar="EMPTY"
nlabel=0
empty=Label(rack,text="",width=2, height=2,font=("Arial Bold", 16),bg='burlywood4',justify=CENTER)
empty.grid(row=0, column=0,padx=10,pady=10)
#----Create column headers
for ic in range (Ncols[iselect]):
chdr=Label(rack,text=str(ic),width=2, height=2,font=("Arial Bold", 16),bg='burlywood4',justify=CENTER)
chdr.grid(row=0,column=(1+ic),padx=10,pady=10)
#-----Create row headers
for ir in range (Nrows[iselect]):
rhdr=Label(rack,text=str(ir),width=2, height=2,font=("Arial Bold", 16),bg='burlywood4',justify=CENTER)
rhdr.grid(row=(1+ir),column=0,padx=10,pady=10)
#-----Create Body
for rack_row in range (0,Nrows[iselect]):
for rack_col in range (0,Ncols[iselect]):
new_label=Label(rack,text=textvar,width=15,height=6, justify=CENTER)
for i in range(nbottles):
if(bottles[i].bin_no==iselect and bottles[i].irow==rack_row and bottles[i].icol==rack_col):
newtext=str("id="+str(bottles[i].bottle_id)+" vtg="+str(bottles[i].vintage) +"\n"+str(bottles[i].winery)+"\n"+ str(bottles[i].varietal))
new_label.config(text=newtext)
new_label.grid(row=rack_row+1,column=1+rack_col,padx=10,pady=10)
#-----Create and pack select_frame into root
select_frame=Frame(root, width=800, height=300)
select_frame.pack()
#-----Create option menu (cat) and grid in select frame
cat_menu=ttk.OptionMenu(select_frame,select_cat,*cat_list,command=update_cat)
cat_menu.config(width=10)
cat_menu.grid(column=0, row=0,padx=10,pady=10)
#-----Create option menu (varietal) and grid in select frame
varietal_menu=ttk.OptionMenu(select_frame, select_var,
*varietal_list,command=update_var)
varietal_menu.config(width=10)
varietal_menu.grid(column=1, row=0,padx=10,pady=10)
#-----Create option menu (winery) and grid in select frame
winery_menu=ttk.OptionMenu(select_frame, select_winery,*winery_list,command=update_winery)
winery_menu.config(width=10)
winery_menu.grid(column=2, row=0,padx=10,pady=10)
#-----Create option menu (rack) and grid in select frame
rack_menu=ttk.OptionMenu(select_frame, select_rack,*rack_list,command=update_rack)
rack_menu.config(width=10)
rack_menu.grid(column=3, row=0,padx=10,pady=10)
####################################################
# BOTTLE FRAME
####################################################
bottle_frame=Frame(root)
bottle_frame.pack(pady=20)
#--- BOTTLE FRAME FUNCTIONS
def select_record(event):
global r_vals
# clear entry box
bot_id_entry.delete(0,END)
bot_winery_entry.delete(0,END)
bot_var_entry.delete(0,END)
bot_vin_entry.delete(0,END)
bot_cat_entry.delete(0,END)
bot_com_entry.delete(0,END)
bot_bin_entry.delete(0,END)
bot_row_entry.delete(0,END)
bot_col_entry.delete(0,END)
# Grab record and values
r_select=bottle_tree.focus()
r_vals=bottle_tree.item(r_select,'values')
# Enter r_vals into entry boxes
bot_id_entry.insert(0,r_vals[0])
bot_winery_entry.insert(0,r_vals[1])
bot_var_entry.insert(0,r_vals[2])
bot_vin_entry.insert(0,r_vals[3])
bot_cat_entry.insert(0,r_vals[4])
bot_com_entry.insert(0,r_vals[5])
bot_bin_entry.insert(0,r_vals[6])
bot_row_entry.insert(0,r_vals[7])
bot_col_entry.insert(0,r_vals[8])
bottle_frame=Frame(root)
bottle_frame.pack(pady=20)
# create Treeview Scrollbar within bottle_frame
bottle_scroll=Scrollbar(bottle_frame)
bottle_scroll.pack(side=RIGHT,fill=Y)
style=ttk.Style()
style.theme_use("default")
# Create an object of Style widget
style.configure("Treeview", background= "#D3D3D3", foreground="black",rowheight=25, fieldbackground= "#D3D3D3")
style.map("Treeview", background=[('selected','blue')])
# create Treeview
bottle_tree=ttk.Treeview(bottle_frame,yscrollcommand=bottle_scroll.set)
bottle_tree.pack()
#Configure the scrollbar
bottle_scroll.config(command=bottle_tree.yview)
bottle_scroll.config(command=bottle_tree.yview)
# Add a Treeview widget
bottle_tree['columns']=("Bottle_id", "winery","varietal","vintage",
"category","comment","bin_no","row","col")
bottle_tree.column("#0", width=0)
bottle_tree.heading("#0",text="", anchor=W)
bottle_tree.column("#1", width=60, anchor=CENTER)
bottle_tree.heading("#1", text="Bottle_id")
bottle_tree.column("#2",width=100, anchor=CENTER)
bottle_tree.heading("#2", text="winery")
bottle_tree.column("#3",width=100, anchor=CENTER)
bottle_tree.heading("#3", text="varietal")
bottle_tree.column("#4",width=40, anchor=CENTER)
bottle_tree.heading("#4", text="vintage")
bottle_tree.column("#5",width=60, anchor=CENTER)
bottle_tree.heading("#5", text="category")
bottle_tree.column("#6",width=150, anchor=CENTER)
bottle_tree.heading("#6", text="comment")
bottle_tree.column("#7",width=40, anchor=CENTER)
bottle_tree.heading("#7",text="bin_no")
bottle_tree.column("# 8",width=40, anchor=CENTER)
bottle_tree.heading("#8", text="row")
bottle_tree.column("#9",width=40, anchor=CENTER)
bottle_tree.heading("#9", text="col")
bottle_tree.bind("<ButtonRelease-1>", select_record)
####################################################
# EDIT FRAME
####################################################
edit_frame=LabelFrame(root, text="Edit")
edit_frame.pack(fill="x", padx=10, pady=10)
bot_id_label=Label(edit_frame, text="Bottle ID")
bot_id_label.grid(row=0, column=0, padx=10, pady=10)
bot_id_entry=Entry(edit_frame)
bot_id_entry.grid(row=0, column=1, padx=10, pady=10)
bot_winery_label=Label(edit_frame, text="Winery")
bot_winery_label.grid(row=0, column=2, padx=10, pady=10)
bot_winery_entry=Entry(edit_frame,bg='lightcyan')
bot_winery_entry.grid(row=0, column=3, padx=10, pady=10)
bot_var_label=Label(edit_frame, text="Varietal")
bot_var_label.grid(row=0, column=4, padx=10, pady=10)
bot_var_entry=Entry(edit_frame,bg='lightcyan')
bot_var_entry.grid(row=0, column=5, padx=10, pady=10)
bot_vin_label=Label(edit_frame, text="Vintage")
bot_vin_label.grid(row=1, column=0, padx=10, pady=10)
bot_vin_entry=Entry(edit_frame,bg='lightcyan')
bot_vin_entry.grid(row=1, column=1, padx=10, pady=10)
bot_cat_label=Label(edit_frame, text="Category")
bot_cat_label.grid(row=1, column=2, padx=10, pady=10)
bot_cat_entry=Entry(edit_frame,bg='lightcyan')
bot_cat_entry.grid(row=1, column=3, padx=10, pady=10)
bot_com_label=Label(edit_frame, text="Comment")
bot_com_label.grid(row=1, column=4, padx=10, pady=10)
bot_com_entry=Entry(edit_frame,bg='lightcyan')
bot_com_entry.grid(row=1, column=5, padx=10, pady=10)
bot_bin_label=Label(edit_frame, text="Bin No.")
bot_bin_label.grid(row=2, column=0, padx=10, pady=10)
bot_bin_entry=Entry(edit_frame,bg='lightcyan')
bot_bin_entry.grid(row=2, column=1, padx=10, pady=10)
bot_row_label=Label(edit_frame, text="Row No.")
bot_row_label.grid(row=2, column=2, padx=10, pady=10)
bot_row_entry=Entry(edit_frame,bg='lightcyan')
bot_row_entry.grid(row=2, column=3, padx=10, pady=10)
bot_col_label=Label(edit_frame, text="Column No.")
bot_col_label.grid(row=2, column=4, padx=10, pady=10)
bot_col_entry=Entry(edit_frame,bg='lightcyan')
bot_col_entry.grid(row=2, column=5, padx=10, pady=10)
####################################################
# COMMAND FRAME AND COMMAND BUTTONS
####################################################
com_frame=LabelFrame(root, text="Commands")
com_frame.pack(pady=10)
def edit_bottle():
#Get the record
selected=bottle_tree.focus()
bottle_tree.item(selected, text="", values=[bot_id_entry.get(),
bot_winery_entry.get(),
bot_var_entry.get(),
bot_vin_entry.get(),
bot_cat_entry.get(),
bot_com_entry.get(),
bot_bin_entry.get(),
bot_row_entry.get(),
bot_col_entry.get()])
# Update bottle object
bid=int(bot_id_entry.get())
bottles[bid].update_bottle(bid)
#---------------------------------------------------
# save function: saves all edits to csv file
#---------------------------------------------------
def savecsv():
header = ['bottle_no','winery','varietal','vintage','class','comments','bin_no','row_no','col_no']
with open('Data/Wine-data.csv', 'w', encoding='UTF8') as f:
writer = csv.writer(f)
# write the header
writer.writerow(header)
# write the data from Bottle ojects
for iid in range (nbottles):
data=[bottles[iid].bottle_id,bottles[iid].winery,bottles[iid].varietal,bottles[iid].vintage,
bottles[iid].cat,bottles[iid].comment,bottles[iid].bin_no,bottles[iid].irow,
bottles[iid].icol]
writer.writerow(data)
def add_bottle():
global nbottles
nbottles+=1
new_bottle=Bottle(nbottles,bot_winery_entry.get(),bot_var_entry.get(),
bot_vin_entry.get(),bot_cat_entry.get(),bot_com_entry.get(),bot_bin_entry.get(),
bot_row_entry.get(),bot_col_entry.get())
bottles.append(new_bottle)
bot_id_entry.delete(0,END)
bot_winery_entry.delete(0,END)
bot_var_entry.delete(0,END)
bot_vin_entry.delete(0,END)
bot_cat_entry.delete(0,END)
bot_com_entry.delete(0,END)
bot_bin_entry.delete(0,END)
bot_row_entry.delete(0,END)
bot_col_entry.delete(0,END)
def consume():
bottles[int(r_vals[0])].bin_no=0
bottles[int(r_vals[0])].irow=0
bottles[int(r_vals[0])].icol=0
#---------------------------------------------------
# Buttons in com_frame
#---------------------------------------------------
update_button=Button(com_frame,text="Edit Bottle", command=edit_bottle)
update_button.grid(row=0,column=0, padx=10, pady=10)
save_button=Button(com_frame,text="Save Edited Data",command=savecsv)
save_button.grid(row=0,column=1, padx=10, pady=10)
new_button=Button(com_frame,text="New Bottle",command=add_bottle)
new_button.grid(row=0,column=2, padx=10, pady=10)
consume_button=Button(com_frame,text="Consumed Wine",command=consume)
consume_button.grid(row=0,column=3, padx=10, pady=10)
####################################################
# START TKINTER EVENT MONITORING
####################################################
root.mainloop()
####################################################
# © Donald R. Falkenburg 2023
####################################################