3
\$\begingroup\$

I wrote a small program that generates a GUI for a grocery list (any list honestly). The GUI has the capacity to open a file, save a file, and save then exit the GUI from a file menu. The grocery items are added one at a time to a listbox using a popup window. The added items can be deleted as well. The functionality is pretty minimal, but I was hoping for some feedback with regards to structure and common practice. Any advice would be appreciated.

import tkinter as tk
from tkinter.filedialog import asksaveasfilename,askopenfilename
class NewForm(tk.Toplevel):
 keys = ['Name','Price']
 def __init__(self):
 tk.Toplevel.__init__(self)
 
 self.resizable(False,False)
 self.title('Add item')
 
 self.grab_set()
 
 self.labels={}
 self.variables={}
 
 for key in NewForm.keys:
 self.labels[key] = ''
 self.variables[key] = tk.StringVar()
 
 for label in self.labels.keys():
 frm = tk.Frame(self,relief=tk.RAISED,bd = 2)
 frm.pack(side=tk.TOP,expand=tk.YES,fill=tk.X)
 tk.Label(frm,text=label).pack(side=tk.LEFT)
 ent = tk.Entry(frm,textvar = self.variables[label])
 ent.pack(side=tk.RIGHT)
 tk.Button(self,text='Submit',command=self.Submit).pack(side=tk.TOP)
 
 self.wait_window()
 def Submit(self):
 for variable_value in self.variables.values():
 if len(variable_value.get())==0:
 tk.messagebox.showinfo('Warning','The fields are incomplete!')
 return
 self.destroy()
class Main(tk.Frame):
 def __init__(self,parent = None):
 tk.Frame.__init__(self,parent,relief = tk.RIDGE,bd=4,
 width = 400,height = 300)
 self.master.title('Grocery List')
 self.pack(expand=tk.YES,fill=tk.BOTH)
 parent.minsize(width = 300,height=200)
 parent.maxsize(width = 500,height =400)
 
 self.add_menu()
 self.add_info()
 
 self.add_buttons()
 
 def add_menu(self):
 self.menu = tk.Menu(self.master)
 self.master.config(menu=self.menu)
 
 file = tk.Menu(self.menu,tearoff=False)
 file.add_command(label='Open',command = self.file_open)
 file.add_command(label='Save',command = self.file_save)
 file.add_command(label='Save and Exit',command = self.file_save_exit)
 self.menu.add_cascade(label='File',menu = file)
 
 def add_info(self):
 info_frame = tk.Frame(self,relief=tk.SUNKEN,bd=2)
 info_frame.pack(side=tk.TOP,expand=tk.YES,fill=tk.BOTH)
 self.sbar = tk.Scrollbar(info_frame)
 self.lbox = tk.Listbox(info_frame,relief = tk.SUNKEN,selectmode='multiple')
 
 self.sbar.config(command = self.lbox.yview)
 self.lbox.config(yscrollcommand = self.sbar.set)
 
 self.sbar.pack(side=tk.RIGHT,fill=tk.Y)
 self.lbox.pack(side=tk.TOP,expand = tk.YES,fill=tk.BOTH)
 
 def add_buttons(self):
 frame = tk.Frame(self,relief = tk.RAISED,bd=2)
 frame.pack(side=tk.TOP,expand=tk.YES,fill=tk.BOTH)
 tk.Button(frame,text='Add grocery item',
 command = self.add_item).pack(side=tk.LEFT,
 expand=tk.YES) 
 tk.Button(frame,text='Delete grocery item',
 command = self.delete_item).pack(side=tk.LEFT,
 expand=tk.YES)
 def add_item(self):
 self.popup = NewForm()
 self.update_list()
 
 def delete_item(self):
 idx_to_delete = self.lbox.curselection()
 for idx in idx_to_delete[::-1]:
 self.lbox.delete(idx)
 
 def update_list(self):
 self.lbox.insert(0,self.popup.variables['Name'].get()+', '+self.popup.variables['Price'].get()+'\n')
 
 def file_open(self):
 file = askopenfilename()
 with open(file,'r') as f:
 contents = f.readlines()
 for line in contents:
 self.lbox.insert(0,line)
 
 def file_save(self):
 filename = asksaveasfilename()
 if filename:
 with open(filename,'w') as f:
 for line in self.lbox.get(0,tk.END):
 f.write(line)
 
 def file_save_exit(self):
 self.file_save()
 self.master.destroy()
 
Main(tk.Tk()).mainloop()
toolic
14.4k5 gold badges29 silver badges201 bronze badges
asked Apr 16, 2020 at 18:05
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Simpler

These 2 lines:

contents = f.readlines()
for line in contents:

can be combined into 1:

for line in f.readlines():

This eliminates the intermediate contents variable.

Documentation

The PEP 8 style guide recommends adding docstrings for classes and functions.

It is also helpful to add a docstring to summarize the code at the top:

"""
Generate a grocery list and store it in a file.
"""

Layout

There is inconsistent whitespace around operators and inconsistent usage of blank lines. The black program can be used to automatically reformat the code for consistency.

Comments

It would be worth adding a comment for this line:

for idx in idx_to_delete[::-1]:

It is not obvious what type of variable idx_to_delete is or what [::-1] is doing.

answered Aug 11 at 11:27
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.