Posts: 12
Threads: 3
Joined: Jul 2017
Sep-22-2017, 10:13 PM
(This post was last modified: Sep-22-2017, 10:14 PM by MGallo.)
Hello, I am currently creating a shoe bot, and I'm having trouble adding more inputs for other fields. I already have name and shoesize working (Thanks to someone on here for helping me with that), but I was wondering how I could make more inputs, and export them to a separate file in this format:
{
"first_name": “”,
"last_name": “”,
"address": “”,
"apartment_suite_unit_floor_(optional)": "",
"city/town": “”,
"state": "",
"zipcode": "",
"phone_number": "",
"email": "",
"credit_card_number": "",
"expirationmonth": "",
"expirationyear": "",
"security_code": "",
} Here is the python code so far:
import tkinter as tk
import os
import json
import tkinter.ttk as ttk
import tkinter.messagebox as tm
class ShoeBot:
def __init__(self, parent, filename):
self.roots = parent
self.roots.title('AWD ShoeBot')
# self.roots.geometry('400x200+10+10')
self.treeheight = 19
self.filename = os.path.abspath(filename)
self.fp = None
self.people = {}
if os.path.isfile(self.filename):
self.load_data()
self.changes_made = False
self.this_person = None
self.name = tk.StringVar()
self.shoe_size = tk.StringVar()
'''
HERE
'''
self.build_gui()
self.load_tree()
def build_gui(self):
self.create_main_frame()
self.create_left_frame()
self.create_right_frame()
self.create_bottom_frame()
self.create_tree()
self.create_user_dialog()
self.create_statusbar()
self.roots.protocol("WM_DELETE_WINDOW", self.on_delete)
def create_main_frame(self):
self.main_frame = tk.Frame(self.roots, relief=tk.RAISED)
self.main_frame.grid(row=0, column=0, sticky='nsew')
self.main_frame.columnconfigure(0, weight=1)
self.main_frame.rowconfigure(0, weight=1)
self.main_frame.pack(pady=5, padx=5)
def create_left_frame(self):
self.left_frame = tk.Frame(self.main_frame, relief=tk.SUNKEN)
self.left_frame.grid(row=0, rowspan=self.treeheight, column=0, columnspan=2, sticky='ns')
def create_right_frame(self):
self.right_frame = tk.Frame(self.main_frame, relief=tk.SUNKEN)
self.right_frame.grid(row=0, rowspan=self.treeheight, column=2, columnspan=10, sticky='ns')
def create_bottom_frame(self):
self.bottom_frame = tk.Frame(self.main_frame, relief=tk.SUNKEN)
self.bottom_frame.grid(row=self.treeheight + 1, column=0, columnspan=11, sticky='ew')
def create_tree(self):
treestyle = ttk.Style()
treestyle.configure('Treeview.Heading', foreground='white',
borderwidth=2, background='SteelBlue',
rowheight=self.treeheight,
height=3)
self.tree = ttk.Treeview(self.left_frame,
height=self.treeheight,
padding=(2, 2, 2, 2),
columns='Name',
selectmode="extended")
self.tree.column('#0', stretch=tk.YES, width=180)
self.tree.tag_configure('monospace', font='courier')
treescrolly = tk.Scrollbar(self.left_frame, orient=tk.VERTICAL,
command=self.tree.yview)
treescrolly.grid(row=0, rowspan=self.treeheight, column=1, sticky='ns')
treescrollx = tk.Scrollbar(self.left_frame, orient=tk.HORIZONTAL,
command=self.tree.xview)
treescrollx.grid(row=self.treeheight + 1, column=0, columnspan=2, sticky='ew')
self.tree.configure(yscroll=treescrolly)
self.tree.configure(xscroll=treescrollx)
self.tree.grid(row=0, rowspan=self.treeheight, column=0, sticky='nsew')
self.tree.bind('<Double-1>', self.name_selected)
def clear_entry(self):
self.nameE.delete(0, 'end')
self.shoeSizeE.delete(0, 'end')
'''
HERE
'''
def clear_tree(self):
all_children = self.tree.get_children()
for item in all_children:
self.tree.delete(item)
def load_tree(self):
self.clear_tree()
keys = list(self.people.keys())
keys.sort()
for key in keys:
self.tree.insert('', 'end', text='{}'.format(key))
def create_user_dialog(self):
self.intruction = tk.Label(self.right_frame, text='Enter Information Below\n')
self.intruction.grid(row=0, column=0, sticky='nse')
self.nameL = tk.Label(self.right_frame, text='Name: ')
self.shoeSizeL = tk.Label(self.right_frame, text='Shoe Size: ')
'''
HERE
'''
self.nameL.grid(row=1, column=0, sticky='w')
self.shoeSizeL.grid(row=2, column=0, sticky='w')
'''
HERE
'''
self.nameE = tk.Entry(self.right_frame, textvariable=self.name)
self.shoeSizeE = tk.Entry(self.right_frame, textvariable=self.shoe_size)
'''
HERE
'''
self.nameE.grid(row=1, column=1)
self.shoeSizeE.grid(row=2, column=1)
'''
HERE
'''
signupButton = tk.Button(self.right_frame, text='Create', command=self.add_person)
signupButton.grid(row=4, column=0, sticky='w')
removeButton = tk.Button(self.right_frame, text='Delete', command=self.remove_person)
removeButton.grid(row=4, column=1, sticky='w')
self.spacer = tk.Label(self.right_frame, bd=0)
self.spacer.grid(row=5, column=0)
def create_statusbar(self):
self.sb = tk.Frame(self.bottom_frame)
self.sb.grid(row=0, column=0, sticky='nsew')
def on_delete(self):
if self.changes_made:
self.save_data()
self.roots.destroy()
def load_data(self):
with open(self.filename) as fp:
self.people = json.load(fp)
def save_data(self):
with open(self.filename, 'w') as fo:
json.dump(self.people, fo)
def add_person(self):
name = self.name.get()
shoesize = self.shoe_size.get()
'''
HERE
'''
if len(name) == 0 or len(shoesize) == 0:
'''
HERE
'''
tm.showerror('Add Person', 'Missing data')
else:
self.people[name] = {'shoesize': shoesize}
self.tree.insert('', 'end', text='{}'.format(name))
self.changes_made = True
self.clear_entry()
msg = 'Added {}'.format(name)
'''
HERE
'''
def remove_person(self):
name = self.name.get()
if len(name) == 0:
tm.showerror('Remove Person', 'No Name')
else:
del self.people[name]
print(f'People: {self.people}')
self.changes_made = True
self.load_tree()
self.clear_entry()
def name_selected(self, event):
curitem = self.tree.focus()
nidx = self.tree.item(curitem)
name = nidx['text']
shoesize = self.people[name]['shoesize']
print('You selected {} who wears size {} shoe'.format(name, shoesize))
# do stuff with selected person
'''
HERE
'''
'''
HERE
'''
def find_person(self):
'''
HERE
'''
try:
person = self.name.get()
self.this_person = self.people[person]
print('found {} shoesize: {}'.format(self.this_person[name], self.this_person[name]['shoesize']))
except:
'Adding {} shoesize: {}'.format(self.name.get(), self.shoe_size.get())
self.add_person()
self.this_person = self.people[person]
self.name.set('')
self.shoe_size.set('')
return self.this_person
def main():
root = tk.Tk()
sb = ShoeBot(root, filename='PeopleFile.json')
root.mainloop()
if __name__ == '__main__':
main() Thanks!
-MGallo
Posts: 11,859
Threads: 472
Joined: Sep 2016
Sep-22-2017, 10:19 PM
(This post was last modified: Sep-22-2017, 10:19 PM by Larz60+.)
What about the code i posted?? I't will allow you to have as many as you wish
And why the new post?
Posts: 12
Threads: 3
Joined: Jul 2017
(Sep-22-2017, 10:19 PM)Larz60+ Wrote: What about the code i posted?? I't will allow you to have as many as you wish
And why the new post?
I thought you said I was on my own now, and I'm having trouble adding new fields; I keep getting errors. Also, the program that we already made takes the values in the dictionary form as I showed above.
Posts: 11,859
Threads: 472
Joined: Sep 2016
Sep-23-2017, 10:42 AM
(This post was last modified: Sep-23-2017, 10:42 AM by Larz60+.)
Ok, I'll give you a start.
your list, which I assume is what you want to save in the file:
Since you are adding so much information, I would suggest that you also
include a customer id, otherwise you're going to run into problems when
someone has same name.
Now since this is the case, the treeview needs to show that customer number, name, and probably zipcode
in order to make the person unique.
{
'first_name': '',
'last_name':'',
'address': '',
'apartment_suite_unit_floor_(optional)':'',
'city/town': '',
'state': '',
'zipcode': ',
'phone_number': ',
'email': ',
'credit_card_number': '',
'expiration_month': '',
'expiration_year': '',
'security_code': '',
} I'll do: 'first_name', 'last_name' and 'zipcode'
The rest will basically be a repeat of these.
Give me a while
Posts: 12
Threads: 3
Joined: Jul 2017
(Sep-23-2017, 10:42 AM)Larz60+ Wrote: I'll do: 'first_name', 'last_name' and 'zipcode'
The rest will basically be a repeat of these.
Give me a while
Thank you so much again! :D
Posts: 11,859
Threads: 472
Joined: Sep 2016
Sep-23-2017, 11:21 PM
(This post was last modified: Sep-23-2017, 11:21 PM by Larz60+.)
This is turning out to be a lot more than I bargained for.
I seldom do this sort of application writing on the forum, you just caught me
while in the mood to write code.
This will take a bit more work, and I'm doing it between other tasks.
Had to expand it in order to make it work correctly, had I known that you wanted
all the other fields, and persistence, I would have gone about it differently.
one thing that is always a problem is selecting customers with the same name, city, state and
even the same home ... (Father and son for example).
To compensate for this, i added a sequence number.
This also creates a delete problem, for example which John Smith to delete.
The data structure has changed because of this, it's now a dictionary, with a hash key, and a
list of people matching that hash code.
I'll explain more later, but here's what you are going to have to do after I post the code: - change from storage in json file to a database, I think sqlite3 is quite adequate for this application.
- add remaining fields. All you have to do is examine how the address field was entered, and follow
the pattern for the remaining fields.
- examine the code and understand how it works.
- You can get someone to do the work for you if you don't want to do it yourself, but you will have
- to post that request in the jobs section, and may have to offer some sort of compensation.
- You can still ask for advise on specific questions, but don't expect someone to answer 10
questions at one time.
- if you find that don't understand certain concepts, ask and I or someone else will at least point you to a tutorial
or other source of information, And may very well answer it directly.
I'll probably post the finished code tomorrow (not a promise, football takes precedence)
but here's a peek at what this is looking like:
click to enlarge
Posts: 12
Threads: 3
Joined: Jul 2017
Posts: 11,859
Threads: 472
Joined: Sep 2016
Oct-02-2017, 03:51 PM
(This post was last modified: Oct-02-2017, 03:51 PM by Larz60+.)
This was posted on the original thread (that's only on thread should be created for the same topic, got confused)
So this is a duplicate post:
From 'Window not appearing #15' at https://python-forum.io/Thread-Window-No...ing?page=2'
------------------------------- duplicate -------------------------------
Well, this has been quite an undertaking:
I said I would post last night, but there was too many loose ends.
There are still several methods here that don't work correctly and
it may take a while longer to complete.
Right now, about the only thing that seems to be solid is the add function
deletes are almost working, but not there yet.
I thought I'd post anyway so that you can start to get an idea of what's what.
As I stated before, the self.people dictionary will need to be replaced by a relational
database, suggest sqlite3. This will eliminate the json file. As is, so long as you have a reasonable
amount of memory it will hold quite a few people, before memory runs out.
the first module must be named 'MakeStateFile.py' as it is imported by the main script
import json
import os
class MakeStateFiles:
def __init__(self):
self.states = {
'USA': {
'Alabama': 'AL',
'Alaska': 'AK',
'Arizona': 'AZ',
'Arkansas': 'AR',
'California': 'CA',
'Colorado': 'CO',
'Connecticut': 'CT',
'Delaware': 'DE',
'District of Columbia': 'DC',
'Florida': 'FL',
'Georgia': 'GA',
'Hawaii': 'HI',
'Idaho': 'ID',
'Illinois': 'IL',
'Indiana': 'IN',
'Iowa': 'IA',
'Kentucky': 'KY',
'Kansas': 'KS',
'Louisiana': 'LA',
'Maine': 'ME',
'Maryland': 'MD',
'Massachusetts': 'MA',
'Michigan': 'MI',
'Mississippi': 'MS',
'Missouri': 'MO',
'Montana': 'MT',
'Nebraska': 'NE',
'Nevada': 'NV',
'New Hampshire': 'NH',
'New Jersey': 'NJ',
'New Mexico': 'NM',
'New York': 'NY',
'North Carolina': 'NC',
'North Dakota': 'ND',
'Ohio': 'OH',
'Oklahoma': 'OK',
'Oregon': 'OR',
'Pennsylvania': 'PA',
'Rhode Island': 'RI',
'South Carolina': 'SC',
'South Dakota': 'SD',
'Tennessee': 'TN',
'Texas': 'TX',
'Utah': 'UT',
'Vermont': 'VT',
'Virginia': 'VA',
'Washington': 'WA',
'West Virginia': 'WV',
'Wisconsin': 'WI',
'Wyoming': 'WY'
},
'Canada': {
'Alberta': 'AB',
'British Columbia': 'BC',
'Manitoba': 'MB',
'New Brunswick': 'NB',
'Newfoundland': 'NF',
'Northwest Territory': 'NT',
'Nova Scotia': 'NS',
'Nunavut': 'NU',
'Ontario': 'ON',
'Prince Edward Island': 'PE',
'Quebec': 'QC',
'Saskatchewan': 'SK',
'Yukon Territory': 'YT'
},
'Mexico': {
'Aguascalientes': 'AG',
'Baja California': 'BJ',
'Baja California Sur': 'BS',
'Campeche': 'CP',
'Chiapas': 'CH',
'Chihuahua': 'CI',
'Coahuila': 'CU',
'Colima': 'CL',
'Distrito Federal': 'DF',
'Durango': 'DG',
'Guanajuato': 'GJ',
'Guerrero': 'GR',
'Hidalgo': 'HG',
'Jalisco': 'JA',
'Mexico': 'EM',
'Michoacan': 'MH',
'Morelos': 'MR',
'Nayarit': 'NA',
'Nuevo': 'Leon NL',
'Oaxaca': 'OA',
'Puebla': 'PU',
'Queretaro': 'QA',
'Quintana': 'Roo QR',
'San Luis Potosi': 'SL',
'Sinaloa': 'SI',
'Sonora': 'SO',
'Tabasco': 'TA',
'Tamaulipas': 'TM',
'Tlaxcala': 'TL',
'Veracruz': 'VZ',
'Yucatan': 'YC',
'Zacatecas': 'ZT',
}
}
self.stup = ('USA','Alabama','Alaska','Arizona','Arkansas','California','Colorado',
'Connecticut','Delaware','District of Columbia', 'Florida','Georgia','Hawaii',
'Idaho','Illinois','Indiana','Iowa','Kentucky','Kansas','Louisiana','Maine',
'Maryland','Massachusetts','Michigan','Mississippi','Missouri','Montana',
'Nebraska','Nevada','New Hampshire','New Jersey','New Mexico','New York',
'North Carolina','North Dakota','Ohio','Oklahoma','Oregon','Pennsylvania',
'Rhode Island','South Carolina','South Dakota','Tennessee','Texas','Utah',
'Vermont','Virginia','Washington','West Virginia','Wisconsin','Wyoming',
' ','Canada', ' ', 'Alberta','British Columbia','Manitoba','New Brunswick',
'Newfoundland','Northwest Territory','Nova Scotia','Nunavut','Ontario',
'Prince Edward Island','Quebec','Saskatchewan','Yukon Territory',' ','Mexico',
' ','Aguascalientes','Baja California', 'Baja California Sur','Campeche',
'Chiapas','Chihuahua','Coahuila','Colima','Distrito Federal', 'Durango',
'Guanajuato','Guerrero','Hidalgo','Jalisco', 'Mexico',' ', 'Michoacan',
'Morelos','Nayarit','Nuevo','Oaxaca','Puebla','Queretaro','Quintana',
'San Luis Potosi','Sinaloa','Sonora', 'Tabasco','Tamaulipas','Tlaxcala',
'Veracruz','Yucatan','Zacatecas')
datapath = os.path.abspath('.')
datapath = '{}\data'.format(datapath)
if not os.path.exists(datapath):
os.makedirs(datapath)
with open('data/States.json', 'w') as state_file:
json.dump(self.states, state_file)
with open('data/StateTuples.json', 'w') as state_tuples:
json.dump(self.stup, state_tuples)
if __name__ == '__main__':
MakeStateFiles()
state_dict = {}
with open('data/States.json', 'r') as f:
state_dict = json.load(f)
# Test dictionary
for key, value in state_dict.items():
for state_name, state_abbr in value.items():
print(f'country: {key}, state_abbr: {state_abbr} state_name: {state_name}') the main program can be named whatever you like:
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as tm
import MakeStateFile as msf
import os
import json
import re
class ShoeBot:
def __init__(self, parent):
self.parent = parent
self.parent.title('AWD ShoeBot')
datapath = os.path.abspath('.')
datapath = '{}\data'.format(datapath)
if not os.path.exists(datapath):
msf.MakeStateFiles()
self.tree_rows = 18
self.left_bottom = self.tree_rows + 2
self.dup_tree_rows = 10
self.textbox_rows = 14
self.treestyle = ttk.Style()
self.treestyle.configure('Treeview',
foreground='white',
borderwidth=2,
background='SteelBlue',
rowheight=self.tree_rows,
height=self.tree_rows)
self.filename = os.path.abspath('data/PeopleFile.json')
self.fp = None
self.people = None
self.person_found = None
if os.path.isfile(self.filename):
with open(self.filename) as people_file:
self.people = json.load(people_file)
else:
self.people = {}
self.changes_made = False
self.this_person = None
with open('data/StateTuples.json') as state_tuples_file:
self.states = json.load(state_tuples_file)
print(f'self.states: {self.states}')
with open('data/States.json') as state_dict_file:
self.state_dict = json.load(state_dict_file)
print(f'self.state_dict: {self.state_dict}')
self.selected_person = None
self.last_name = tk.StringVar()
self.first_name = tk.StringVar()
self.address1 = tk.StringVar()
self.address2 = tk.StringVar()
self.city = tk.StringVar()
self.state_name = tk.StringVar()
self.state_abbr = tk.StringVar()
self.country = tk.StringVar()
self.zipcode = tk.StringVar()
self.shoe_size = tk.StringVar()
self.this_item = None
self.build_gui()
self.load_tree()
def build_gui(self):
self.create_main_frame()
self.create_left_frame()
self.create_right_frame()
self.create_bottom_frame()
self.create_tree()
self.create_textbox()
self.create_user_dialog()
self.create_statusbar()
self.parent.protocol("WM_DELETE_WINDOW", self.on_delete)
def create_main_frame(self):
self.main_frame = tk.Frame(self.parent, bd=2, padx=4, pady=4, relief=tk.RAISED)
self.main_frame.grid(row=0, column=0, sticky='nseww')
self.main_frame.columnconfigure(0, weight=1)
self.main_frame.rowconfigure(0, weight=1)
self.main_frame.pack(pady=5, padx=5)
def create_left_frame(self):
self.left_frame = tk.Frame(self.main_frame, bd=2, padx=4, pady=4, relief=tk.SUNKEN)
self.left_frame.grid(row=0, rowspan=self.tree_rows, column=0, columnspan=2, sticky='ns')
def create_right_frame(self):
self.right_frame = tk.Frame(self.main_frame, bd=2, padx=4, pady=4, relief=tk.SUNKEN)
self.right_frame.grid(row=0, rowspan=self.tree_rows, column=2, columnspan=10, sticky='ns')
def create_bottom_frame(self):
self.bottom_frame = tk.Frame(self.main_frame, bd=2, padx=4, pady=4, relief=tk.SUNKEN)
self.bottom_frame.grid(row=self.tree_rows + 1, column=0, columnspan=11, sticky='ew')
def create_tree(self):
self.tree = ttk.Treeview(self.left_frame,
height=self.tree_rows,
padding=(2, 2, 2, 2),
columns=1,
selectmode="extended",
style='Treeview')
self.tree.heading('#0', text='Person, Name, address', anchor='w')
self.tree.column('#0', stretch=tk.NO, width=400)
self.tree.tag_configure('monospace', font='courier')
treescrolly = tk.Scrollbar(self.left_frame, orient=tk.VERTICAL,
command=self.tree.yview)
treescrollx = tk.Scrollbar(self.left_frame, orient=tk.HORIZONTAL,
command=self.tree.xview)
self.tree.grid(row=0, rowspan=self.tree_rows, column=0, sticky='nsew')
treescrolly.grid(row=0, rowspan=self.tree_rows, column=1, sticky='ns')
treescrollx.grid(row=self.tree_rows + 1, column=0, columnspan=2, sticky='ew')
self.tree.configure(yscroll=treescrolly)
self.tree.configure(xscroll=treescrollx)
self.tree.bind('<Double-1>', self.name_selected)
def create_textbox(self):
self.textbox = tk.Text(self.left_frame, bd=2, bg='#CEF6EC', relief=tk.RAISED, width=20, height=self.textbox_rows)
txscrolly = tk.Scrollbar(self.left_frame, orient=tk.VERTICAL, command=self.textbox.yview)
txscrollx = tk.Scrollbar(self.left_frame, orient=tk.HORIZONTAL, command=self.textbox.xview)
txscrollx.config(command=self.textbox.xview)
txscrolly.config(command=self.textbox.yview)
self.textbox.grid(row=self.left_bottom, rowspan=self.textbox_rows, column=0,
padx=2, pady=2, sticky='nsew')
txscrolly.grid(row=self.left_bottom, rowspan=self.textbox_rows, column=1, sticky='ns')
txscrollx.grid(row=self.left_bottom + self.textbox_rows, column=0, columnspan=2, sticky='ew')
self.textbox.insert('end', 'Test message:\n')
def create_user_dialog(self):
self.intruction = tk.Label(self.right_frame, text='Enter Information Below:\n')
self.intruction.grid(row=0, column=0, sticky='nse')
self.first_name_l = tk.Label(self.right_frame, text='First Name: ')
self.first_name_e = tk.Entry(self.right_frame, textvariable=self.first_name)
self.first_name_l.grid(row=1, column=0, sticky='w')
self.first_name_e.grid(row=1, column=1, columnspan=8, sticky='ew')
self.last_name_l = tk.Label(self.right_frame, text='Last Name: ')
self.last_name_e = tk.Entry(self.right_frame, textvariable=self.last_name)
self.last_name_l.grid(row=2, column=0, sticky='w')
self.last_name_e.grid(row=2, column=1, columnspan=8, sticky='ew')
self.address1_l = tk.Label(self.right_frame, text='Address 1: ')
self.address1_e = tk.Entry(self.right_frame, textvariable=self.address1)
self.address1_l.grid(row=3, column=0, sticky='w')
self.address1_e.grid(row=3, column=1, columnspan=8, sticky='ew')
self.address2_l = tk.Label(self.right_frame, text='Address 2: ')
self.address2_e = tk.Entry(self.right_frame, textvariable=self.address2)
self.address2_l.grid(row=4, column=0, sticky='w')
self.address2_e.grid(row=4, column=1, columnspan=8, sticky='ew')
self.city_l = tk.Label(self.right_frame, text='City: ')
self.city_e = tk.Entry(self.right_frame, textvariable=self.city)
self.city_l.grid(row=5, column=0, sticky='w')
self.city_e.grid(row=5, column=1, columnspan=2, sticky='ew')
self.state_l = tk.Label(self.right_frame, text='State: ')
self.state_e = ttk.Combobox(self.right_frame, textvariable=self.state_name)
self.state_e['values'] = self.states
self.state_l.grid(row=5, column=3, sticky='w')
self.state_e.grid(row=5, column=4, columnspan=2, sticky='ew')
self.state_e.bind("<<ComboboxSelected>>", self.set_state)
self.state_e.bind("<FocusIn>", self.set_focus)
self.zipcode_l = tk.Label(self.right_frame, text='Zip Code: ')
self.zipcode_e = tk.Entry(self.right_frame, textvariable=self.zipcode)
self.zipcode_l.grid(row=6, column=0, sticky='w')
self.zipcode_e.grid(row=6, column=1, sticky='w')
self.country_l = tk.Label(self.right_frame, text='Country: ')
self.country_e = tk.Entry(self.right_frame, textvariable=self.country)
self.country_l.grid(row=7, column=0, sticky='w')
self.country_e.grid(row=7, column=1, sticky='w')
self.country_e.configure(state='readonly')
self.shoe_size_l = tk.Label(self.right_frame, text='Shoe Size: ')
self.shoe_size_e = tk.Entry(self.right_frame, textvariable=self.shoe_size)
self.shoe_size_l.grid(row=8, column=0, sticky='w')
self.shoe_size_e.grid(row=8, column=1, sticky='w')
self.spacer1 = ttk.Separator(self.right_frame)
self.spacer1.grid(row=9, rowspan=2, column=0)
create_button = tk.Button(self.right_frame, text='Create', command=self.add_person)
create_button.grid(row=11, column=0, sticky='w')
cancel_button = tk.Button(self.right_frame, text='Cancel', command=self.cancel)
cancel_button.grid(row=11, column=1, sticky='w')
remove_button = tk.Button(self.right_frame, text='Delete')
remove_button.grid(row=11, column=2, sticky='w')
remove_button.bind('<Button-1>', self.name_selected)
self.spacer2 = ttk.Separator(self.right_frame)
self.spacer2.grid(row=12, rowspan=2, column=0)
self.dup_tree = ttk.Treeview(self.right_frame,
height=self.tree_rows,
padding=(2, 2, 2, 2),
columns='Name',
selectmode="extended",
style='Treeview')
self.dup_tree.heading('#0', text='Duplicate Name Selection')
self.dup_tree.column('#0', stretch=tk.YES, width=200)
self.dup_tree.tag_configure('monospace', font='courier')
self.dw_treescrolly = tk.Scrollbar(self.right_frame, orient=tk.VERTICAL,
command=self.dup_tree.yview)
self.dw_treescrollx = tk.Scrollbar(self.right_frame, orient=tk.HORIZONTAL,
command=self.dup_tree.xview)
self.dup_tree.configure(yscroll=self.dw_treescrolly)
self.dup_tree.configure(xscroll=self.dw_treescrollx)
def hide_dup_tree(self):
self.dup_tree.forget()
self.dw_treescrolly.forget()
self.dw_treescrollx.forget()
self.dup_tree.unbind('<Double-1>')
def show_dup_tree(self):
self.dup_tree.grid(row=14, rowspan=self.dup_tree_rows, column=0, columnspan=6, sticky='nsew')
self.dw_treescrolly.grid(row=14, rowspan=self.dup_tree_rows, column=6, sticky='ns')
self.dw_treescrollx.grid(row=self.dup_tree_rows + 14, column=0, columnspan=6, sticky='ew')
self.dup_tree.bind('<Double-1>', self.person_selected)
def create_key(self, fname, lname):
return f'{lname}{fname}'
def name_selected(self, event):
# todo - new indexing
origin = str(event.widget)
widget = event.widget
fromtree = False
address1 = ''
if '!treeview' in origin:
curitem = self.tree.focus()
nidx = self.tree.item(curitem)
entry = nidx['text']
# hack to get address from Treeview element
# If anything is added to the Treeview elements, the following code will have to be changed
address1 = entry[(entry.index('street address:') + 16):]
# look for address hone in on proper dictionary entry
fromtree = True
else:
curitem = self.button.focus()
nidx = self.tree.item(curitem)
entry = nidx['text']
fields = re.split('[, \W]+', entry)
fname = fields[0]
lname = fields[1]
key = self.create_key(fname, lname)
people = self.people[key]
print(f'people: {people}')
self.selected_person = None
last_seq = int(people['last_seq'])
if last_seq > 0:
cur_seq = 0
while(cur_seq <= last_seq):
person = people[str(cur_seq)]
if fromtree:
if person['address1'] != address1:
self.add_to_dups(person)
else:
self.add_to_dups(person)
cur_seq += 1
self.show_dup_tree()
else:
self.selected_person = people['0']
# self.display_person(selected_person)
# else:
# tm.showerror('name_selected', '{} {} not found'.format(fname, lname))
def person_selected():
pass
def select_person_from_dups(self, event):
curitem = self.dup_tree.focus()
nidx = self.tree.item(curitem)
entry = nidx['text']
key = self.create_key(entry['fname'], entry['lname'])
# return self.people[key]
def display_person(self, person):
self.clear_entry()
self.first_name.set(person['fname'])
self.last_name.set(person['lname'])
self.address1.set(person['address1'])
self.address2.set(person['address2'])
self.city.set(person['city'])
self.state_name.set(person['state_name'])
self.state_abbr.set(person['state_abbr'])
self.country.set(person['state_name'])
self.shoe_size.set(person['shoesize'])
self.zipcode.set(person['zip'])
self.parent.update_idletasks()
def add_to_dups(self, person):
# Give enough information to make delete decision
# shoesize because father & son may have same name, address, and hopefully different shoe size
ptext = 'seq: {}, {} {}, {}, {}, {} -- shoe size: {}'\
.format(person['seq'], person['fname'], person['lname'], person['address1'], person['city'],
person['state_abbr'], person['shoesize'])
self.dup_tree.insert('', 'end', text=ptext)
def remove_person(self, event):
# todo - populate dup entry tree
# todo use new indexing
# todo - determine how this method was called, from clicking person in Treeview, or
# todo - from text entry (first & Last Name). If later, need to name
curitem = self.dup_tree.focus()
nidx = self.dup_tree.item(curitem)
entry = nidx['text']
fields = entry.split()
fname = fields[0]
lname = fields[1]
key = self.create_key(fname, lname)
this_item = self.people[key]
print(f'key: {key}, this_item: {this_item}')
self.clear_entry()
self.clear_dup_tree()
def clear_entry(self):
self.first_name_e.delete(0, 'end')
self.last_name_e.delete(0, 'end')
self.address1_e.delete(0, 'end')
self.address2_e.delete(0, 'end')
self.city_e.delete(0, 'end')
self.state = None
self.state_e.set('')
self.zipcode_e.delete(0, 'end')
self.country_e.delete(0, 'end')
self.shoe_size_e.delete(0, 'end')
def clear_tree(self):
all_children = self.tree.get_children()
for item in all_children:
self.tree.delete(item)
def load_tree(self):
# todo -- This one ok
self.clear_tree()
keys = list(self.people.keys())
keys.sort()
for key in keys:
group = self.people[key]
for key, person in group.items():
if key.isnumeric():
ptext = '{} {}, street address: {}'\
.format(person['fname'], person['lname'], person['address1'])
self.tree.insert('', 'end', text=ptext)
def set_focus(self, event):
event.widget.master.focus_set()
def set_state(self, event):
widget = event.widget
state_name = widget.get()
print(f'state_name: {state_name}')
us = self.state_dict['USA']
canada = self.state_dict['Canada']
mexico = self.state_dict['Mexico']
self.state_name.set(state_name)
if state_name in us:
self.state_abbr.set(us[state_name])
self.country.set('USA')
elif state_name in canada:
self.country.set('Canada')
self.state_abbr.set(canada[state_name])
elif state_name in mexico:
self.country.set('Mexico')
self.state_abbr.set(mexico[state_name])
else:
tm.showerror('set_state', 'State {} Not found'.format(state_name))
self.state_name = None
self.country = None
def cancel(self):
self.clear_entry()
def create_statusbar(self):
self.sb = tk.Frame(self.bottom_frame)
self.sb.grid(row=0, column=0, sticky='nsew')
def save_data(self):
with open(self.filename, 'w') as fo:
json.dump(self.people, fo)
def update_seq(self, key):
new_seq = None
if key in self.people:
seq_no = int(self.people[key]['last_seq'])
new_seq = str(int(seq_no) + 1)
else:
new_seq = '0'
self.people[key] = {}
self.people[key]['last_seq'] = new_seq
# self.people[key]['last_seq'] = str(int(new_seq)+1)
return(new_seq)
def add_person(self):
# todo - add check to make sure required fields are populated
# todo use new indexing
new_entry = False
lname = self.last_name.get()
fname = self.first_name.get()
key = self.create_key(fname, lname)
print(f'Add key: {key}')
seq = self.update_seq(key)
print(seq)
new_person = self.people[key][seq] = {}
new_person['lname'] = lname
new_person['fname'] = fname
new_person['seq'] = seq
new_person['address1'] = self.address1.get()
new_person['address2'] = self.address2.get()
new_person['city'] = self.city.get()
new_person['state_name'] = self.state_name.get()
new_person['state_abbr'] =self.state_abbr.get()
new_person['zip'] = self.zipcode.get()
new_person['country'] = self.country.get()
new_person['shoesize'] = self.shoe_size.get()
print(f'self.people 2: {self.people}')
self.save_data()
self.load_tree()
# ival = '{} {} , addr1: {}'.format(fname, lname, seq_no, new_person['address1'])
# self.tree.insert('', 'end', text=ival)
self.clear_entry()
def clear_dup_tree(self):
map(self.dup_tree.delete, self.dup_tree.get_children())
def on_delete(self):
self.parent.destroy()
def main():
root = tk.Tk()
ShoeBot(root)
root.mainloop()
if __name__ == '__main__':
main() Here's a list of what reamains:
Remains to do (in order of priority:
- Change Name Selected, all it should do is select the item being clicked and diaplay the details.
- if Only first and last name selected from entry fields, fill dup list with everyone that has
that name, and allow to finish selection from dup tree.
- Finish delete.
- Problem when starting from entry box: - Thinks it is selecting from dlete tree
before populated
- if last and first name only entered, fill dup list for final selection.
- Fix problem with country not being populated if wrong state chosen and then correct chosen
(after tkinter messgebox display)
- Make sure all necessary fields populated when adding or deleting customer.
- re-arrange order of methods logically
- Decide what to do with Text Box
- replace dictionary with sqlite3 database
- Add zipcode file
- add comments
- add user docs
I may not do all this, but at least it's on the list.
I will turn this into a general customer maintenance program tutorial
so others may benefit form it. For that, I'll probably do a wxpython version as well
as it has a much cleaner and modern look.
Posts: 11,859
Threads: 472
Joined: Sep 2016
New update:
I'm going to take a week break from this as I am getting
tired of looking at it.
Still a few items to do:
Completed Tasks: - Change Name Selected, all it should do is select the item being clicked and diaplay the details. --Done--
- if Only first and last name selected from entry fields, fill dup list with everyone that has that name, and allow to finish selection from dup tree. --Done--
- if last and first name only entered, fill dup list for final selection. --Done--
- Problem when starting from entry box: - Thinks it is selecting from delete tree before populated
- Fix problem with country not being populated if wrong state chosen and then correct chosen (after tkinter messgebox display) -- Done--
- Treeview not loading at start -- Done--
To be done: - hide_dup_tree doesn't hide the dup tree.
- Finish delete.
- Make sure all necessary fields populated when adding or deleting customer.
- re-arrange order of methods logically
- Decide what to do with Text Box
- replace dictionary with sqlite3 database
- Add zipcode file
- add comments - Started -
- add user docs
- Delete unused or replaced methods
ShoeBot.py
# coding=utf-8
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as tm
import MakeStateFile as msf
import os
import json
import re
class ShoeBot:
def __init__(self, parent):
self.parent = parent
self.parent.title('AWD ShoeBot')
datapath = os.path.abspath('.')
datapath = '{}\data'.format(datapath)
if not os.path.exists(datapath):
msf.MakeStateFiles()
self.tree_rows = 18
self.tree_items = {}
self.left_bottom = self.tree_rows + 2
self.dup_tree_rows = 10
self.textbox_rows = 14
self.treestyle = ttk.Style()
self.treestyle.configure('Treeview',
foreground='white',
borderwidth=2,
background='SteelBlue',
rowheight=self.tree_rows,
height=self.tree_rows)
self.filename = os.path.abspath('data/customerFile.json')
self.fp = None
self.customers = None
self.cust_key = None
self.cust_item = None
self.selected_customer = None
if os.path.isfile(self.filename):
with open(self.filename) as customer_file:
self.customers = json.load(customer_file)
else:
self.customers = {}
self.changes_made = False
self.this_customer = None
with open('data/StateTuples.json') as state_tuples_file:
self.states = json.load(state_tuples_file)
with open('data/States.json') as state_dict_file:
self.state_dict = json.load(state_dict_file)
self.selected_customer = None
self.last_name = tk.StringVar()
self.first_name = tk.StringVar()
self.address1 = tk.StringVar()
self.address2 = tk.StringVar()
self.city = tk.StringVar()
self.state_name = tk.StringVar()
self.state_abbr = tk.StringVar()
self.country = tk.StringVar()
self.zipcode = tk.StringVar()
self.shoe_size = tk.StringVar()
self.this_item = None
self.build_gui()
self.load_tree()
def build_gui(self):
self.create_main_frame()
self.create_left_frame()
self.create_right_frame()
self.create_bottom_frame()
self.create_tree()
self.create_textbox()
self.create_user_dialog()
self.create_dup_tree()
self.create_statusbar()
self.parent.protocol("WM_DELETE_WINDOW", self.on_delete)
def create_main_frame(self):
self.main_frame = tk.Frame(self.parent, bd=2, padx=4, pady=4, relief=tk.RAISED)
self.main_frame.grid(row=0, column=0, sticky='nseww')
self.main_frame.columnconfigure(0, weight=1)
self.main_frame.rowconfigure(0, weight=1)
self.main_frame.pack(pady=5, padx=5)
def create_left_frame(self):
self.left_frame = tk.Frame(self.main_frame, bd=2, padx=4, pady=4, relief=tk.SUNKEN)
self.left_frame.grid(row=0, rowspan=self.tree_rows, column=0, columnspan=2, sticky='ns')
def create_right_frame(self):
self.right_frame = tk.Frame(self.main_frame, bd=2, padx=4, pady=4, relief=tk.SUNKEN)
self.right_frame.grid(row=0, rowspan=self.tree_rows, column=2, columnspan=7, sticky='ns')
def create_bottom_frame(self):
self.bottom_frame = tk.Frame(self.main_frame, bd=2, padx=4, pady=4, relief=tk.SUNKEN)
self.bottom_frame.grid(row=self.tree_rows + 1, column=0, columnspan=11, sticky='ew')
def create_tree(self):
self.tree = ttk.Treeview(self.left_frame,
height=self.tree_rows,
padding=(2, 2, 2, 2),
columns=1,
selectmode="extended",
style='Treeview')
self.tree.heading('#0', text='customer, Name, address', anchor='w')
self.tree.column('#0', stretch=tk.NO, width=400)
self.tree.tag_configure('monospace', font='courier')
treescrolly = tk.Scrollbar(self.left_frame, orient=tk.VERTICAL,
command=self.tree.yview)
treescrollx = tk.Scrollbar(self.left_frame, orient=tk.HORIZONTAL,
command=self.tree.xview)
self.tree.grid(row=0, rowspan=self.tree_rows, column=0, sticky='nsew')
treescrolly.grid(row=0, rowspan=self.tree_rows, column=1, sticky='ns')
treescrollx.grid(row=self.tree_rows + 1, column=0, columnspan=2, sticky='ew')
self.tree.configure(yscroll=treescrolly)
self.tree.configure(xscroll=treescrollx)
self.tree.bind('<Double-1>', self.customer_select)
def create_textbox(self):
self.textbox = tk.Text(self.left_frame, bd=2, bg='#CEF6EC', relief=tk.RAISED, width=20, height=self.textbox_rows)
txscrolly = tk.Scrollbar(self.left_frame, orient=tk.VERTICAL, command=self.textbox.yview)
txscrollx = tk.Scrollbar(self.left_frame, orient=tk.HORIZONTAL, command=self.textbox.xview)
txscrollx.config(command=self.textbox.xview)
txscrolly.config(command=self.textbox.yview)
self.textbox.grid(row=self.left_bottom, rowspan=self.textbox_rows, column=0,
padx=2, pady=2, sticky='nsew')
txscrolly.grid(row=self.left_bottom, rowspan=self.textbox_rows, column=1, sticky='ns')
txscrollx.grid(row=self.left_bottom + self.textbox_rows, column=0, columnspan=2, sticky='ew')
self.textbox.insert('end', 'Reserved for future use:\n')
def create_user_dialog(self):
self.intruction = tk.Label(self.right_frame, text='Enter Information Below:\n')
self.intruction.grid(row=0, column=0, columnspan=7, sticky='w')
self.first_name_l = tk.Label(self.right_frame, text='First Name: ')
self.first_name_e = tk.Entry(self.right_frame, textvariable=self.first_name)
self.first_name_l.grid(row=1, column=0, sticky='w')
self.first_name_e.grid(row=1, column=1, columnspan=8, sticky='ew')
self.last_name_l = tk.Label(self.right_frame, text='Last Name: ')
self.last_name_e = tk.Entry(self.right_frame, textvariable=self.last_name)
self.last_name_l.grid(row=2, column=0, sticky='w')
self.last_name_e.grid(row=2, column=1, columnspan=8, sticky='ew')
self.address1_l = tk.Label(self.right_frame, text='Address 1: ')
self.address1_e = tk.Entry(self.right_frame, textvariable=self.address1)
self.address1_l.grid(row=3, column=0, sticky='w')
self.address1_e.grid(row=3, column=1, columnspan=8, sticky='ew')
self.address2_l = tk.Label(self.right_frame, text='Address 2: ')
self.address2_e = tk.Entry(self.right_frame, textvariable=self.address2)
self.address2_l.grid(row=4, column=0, sticky='w')
self.address2_e.grid(row=4, column=1, columnspan=8, sticky='ew')
self.city_l = tk.Label(self.right_frame, text='City: ')
self.city_e = tk.Entry(self.right_frame, textvariable=self.city)
self.city_l.grid(row=5, column=0, sticky='w')
self.city_e.grid(row=5, column=1, columnspan=2, sticky='ew')
self.state_l = tk.Label(self.right_frame, text='State: ')
self.state_e = ttk.Combobox(self.right_frame, textvariable=self.state_name)
self.state_e['values'] = self.states
self.state_l.grid(row=5, column=3, sticky='w')
self.state_e.grid(row=5, column=4, columnspan=2, sticky='ew')
self.state_e.bind("<<ComboboxSelected>>", self.set_state)
self.state_e.bind("<FocusIn>", self.set_focus)
self.zipcode_l = tk.Label(self.right_frame, text='Zip Code: ')
self.zipcode_e = tk.Entry(self.right_frame, textvariable=self.zipcode)
self.zipcode_l.grid(row=5, column=6, sticky='w')
self.zipcode_e.grid(row=5, column=7, sticky='w')
self.country_l = tk.Label(self.right_frame, text='Country: ')
self.country_e = tk.Entry(self.right_frame, textvariable=self.country)
self.country_l.grid(row=7, column=0, sticky='w')
self.country_e.grid(row=7, column=1, sticky='w')
self.country_e.configure(state='readonly')
self.shoe_size_l = tk.Label(self.right_frame, text='Shoe Size: ')
self.shoe_size_e = tk.Entry(self.right_frame, textvariable=self.shoe_size)
self.shoe_size_l.grid(row=8, column=0, sticky='w')
self.shoe_size_e.grid(row=8, column=1, sticky='w')
self.spacer1 = ttk.Separator(self.right_frame)
self.spacer1.grid(row=9, rowspan=2, column=0)
button_frame = tk.Frame(self.right_frame, bd=4, padx=4, pady=4, relief=tk.SUNKEN)
button_frame.grid(row=11, column=0, columnspan=4, sticky='nsew')
self.display_button = tk.Button(button_frame, text='Display', bd=4, padx=4, pady=4, relief=tk.RAISED)
self.display_button.grid(row=0, column=0, sticky='w')
self.display_button.bind('<Button-1>', self.customer_select)
self.create_button = tk.Button(button_frame, text='Create', bd=4, padx=4, pady=4, relief=tk.RAISED)
self.create_button.grid(row=0, column=1, sticky='w')
self.create_button.bind('<Button-1>', self.add_customer)
self.cancel_button = tk.Button(button_frame, text='Cancel', bd=4, padx=4, pady=4, relief=tk.RAISED)
self.cancel_button.grid(row=0, column=2, sticky='w')
self.cancel_button.bind('<Button-1>', self.cancel)
self.remove_button = tk.Button(button_frame, text='Delete', bd=4, padx=4, pady=4, relief=tk.RAISED)
self.remove_button.grid(row=0, column=3, sticky='w')
self.remove_button.bind('<Button-1>', self.remove_customer)
def create_dup_tree(self):
self.spacer2 = ttk.Separator(self.right_frame)
self.spacer2.grid(row=12, rowspan=2, column=0)
self.dup_tree = ttk.Treeview(self.right_frame,
height=self.tree_rows,
padding=(2, 2, 2, 2),
columns='Name',
selectmode="extended",
style='Treeview')
self.dup_tree.heading('#0', text='Duplicate Name Selection')
self.dup_tree.column('#0', stretch=tk.YES, width=400)
self.dup_tree.tag_configure('monospace', font='courier')
self.dw_treescrolly = tk.Scrollbar(self.right_frame, orient=tk.VERTICAL,
command=self.dup_tree.yview)
self.dw_treescrollx = tk.Scrollbar(self.right_frame, orient=tk.HORIZONTAL,
command=self.dup_tree.xview)
self.dup_tree.configure(yscroll=self.dw_treescrolly)
self.dup_tree.configure(xscroll=self.dw_treescrollx)
def hide_dup_tree(self):
self.clear_dup_tree()
self.dup_tree.forget()
self.dw_treescrolly.forget()
self.dw_treescrollx.forget()
self.dup_tree.unbind('<Double-1>')
self.parent.update_idletasks()
def show_dup_tree(self):
self.dup_tree.grid(row=14, rowspan=self.dup_tree_rows, column=0, columnspan=6, sticky='nsew')
self.dw_treescrolly.grid(row=14, rowspan=self.dup_tree_rows, column=6, sticky='ns')
self.dw_treescrollx.grid(row=self.dup_tree_rows + 14, column=0, columnspan=6, sticky='ew')
self.dup_tree.bind('<Double-1>', self.dup_customer_selected)
def load_tree(self):
# todo -- This one ok
self.clear_tree()
keys = list(self.customers.keys())
keys.sort()
cur_index = 1
for key in keys:
cust_key = key
group = self.customers[key]
for ckey, customer in group.items():
if ckey.isnumeric():
ptext = '{} {} - {} {} {}, {} {} {}'\
.format(customer['fname'], customer['lname'], customer['address1'], customer['address2'],
customer['city'], customer['state_name'], customer['zip'], customer['country'])
self.tree.insert('', cur_index, text=ptext)
self.update_tree_items(ckey, cust_key, cur_index, customer)
cur_index += 1
def update_tree_items(self, key, cust_key, cur_index, customer):
"""
Keeps copy of all customers dictionary keys used to fill treeview.
Used as a cross reference when selecting or deleting entries
:param key: <class 'str'> this is the self.customers dictionry key
:param cust_key: <class 'str'> This is the item in the self.customers[key] entry of a the tree entry
:param cur_index: <class 'int'> this is the tree row index
:param customer: <class 'dict'> type dict: this is the customer detail
:return: None
"""
idx = str(cur_index)
self.tree_items[idx] = {}
self.tree_items[idx]['cust_key'] = cust_key
self.tree_items[idx]['cust_entry'] = key
self.tree_items[idx]['fname'] = customer['fname']
self.tree_items[idx]['lname'] = customer['lname']
self.tree_items[idx]['address1'] = customer['address1']
self.tree_items[idx]['address2'] = customer['address2']
self.tree_items[idx]['city'] = customer['city']
self.tree_items[idx]['state_name'] = customer['state_name']
self.tree_items[idx]['zip'] = customer['zip']
self.tree_items[idx]['country'] = customer['country']
def create_key(self, fname, lname):
return f'{lname}{fname}'
def customer_select(self, event):
"""
Run on double click of self.tree item
:param event:
:return:
"""
name = str(event.widget).split(".")[-1]
name = name[1:]
self.cust_key = None
self.cust_item = None
self.selected_customer = None
if name == 'treeview':
curitem = self.tree.focus()
nidx = self.tree.item(curitem)
# The following is a hack, curitem has a value like I002, we want '2'
tree_item_key = str(int(curitem[1:]))
self.cust_key = self.tree_items[tree_item_key]['cust_key']
self.cust_item = self.tree_items[tree_item_key]['cust_entry']
self.selected_customer = self.customers[self.cust_key][self.cust_item]
elif name == 'button':
lname = self.last_name.get()
fname = self.first_name.get()
self.cust_key = self.create_key(fname, lname)
self.selected_customer = self.customers[self.cust_key]
if self.cust_key in self.customers:
self.selected_customer = self.customers[self.cust_key]
self.select_customer_from_dups()
else:
self.cust_key =None
tm.showerror('customer_select', 'Customer not found, check first and last name')
return None
else:
self.cust_key = None
tm.showerror('customer_select', 'Unknown event name: {}'.format(name))
return None
self.display_customer()
def select_customer_from_dups(self):
if self.selected_customer is not None:
self.clear_dup_tree()
last_seq = int(self.selected_customer['last_seq'])
if last_seq == 0:
self.selected_customer = self.selected_customer['0']
else:
for n in range(last_seq + 1):
cid = str(n)
customer = self.selected_customer[cid]
ptext = '{} {} - {} {} {}, {} {} {}'\
.format(customer['fname'], customer['lname'], customer['address1'], customer['address2'],
customer['city'], customer['state_name'], customer['zip'], customer['country'])
self.dup_tree.insert('', 'end', text=ptext)
self.show_dup_tree()
else:
self.cust_key = None
tm.showerror('select_customer_from_dups', 'No selected customer')
return None
def dup_customer_selected(self, event):
curitem = self.dup_tree.focus()
# The following is a hack, curitem has a value like I002, we want '2'
dkey = str(int(curitem[1:]) - 1)
self.selected_customer = self.selected_customer[dkey]
self.display_customer()
self.hide_dup_tree()
def display_customer(self):
if self.selected_customer is not None:
self.clear_entry()
customer = self.selected_customer
print(f'customer: {customer}')
self.first_name.set(customer['fname'])
self.last_name.set(customer['lname'])
self.address1.set(customer['address1'])
self.address2.set(customer['address2'])
self.city.set(customer['city'])
self.state_name.set(customer['state_name'])
self.state_abbr.set(customer['state_abbr'])
self.country.set(customer['country'])
self.shoe_size.set(customer['shoesize'])
self.zipcode.set(customer['zip'])
self.parent.update_idletasks()
def add_to_dups(self, customer):
# Give enough information to make delete decision
# shoesize because father & son may have same name, address, and hopefully different shoe size
ptext = 'seq: {}, {} {}, {}, {}, {} -- shoe size: {}'\
.format(customer['seq'], customer['fname'], customer['lname'], customer['address1'], customer['city'],
customer['state_abbr'], customer['shoesize'])
self.dup_tree.insert('', 'end', text=ptext)
def remove_customer(self, event):
# todo - populate dup entry tree
# todo use new indexing
# todo - determine how this method was called, from clicking customer in Treeview, or
# todo - from text entry (first & Last Name). If later, need to name
curitem = self.dup_tree.focus()
nidx = self.dup_tree.item(curitem)
entry = nidx['text']
fields = entry.split()
fname = fields[0]
lname = fields[1]
key = self.create_key(fname, lname)
this_item = self.customers[key]
self.clear_entry()
self.clear_dup_tree()
def clear_entry(self):
self.first_name_e.delete(0, 'end')
self.last_name_e.delete(0, 'end')
self.address1_e.delete(0, 'end')
self.address2_e.delete(0, 'end')
self.city_e.delete(0, 'end')
self.state = None
self.state_e.set('')
self.zipcode_e.delete(0, 'end')
self.country_e.delete(0, 'end')
self.shoe_size_e.delete(0, 'end')
def clear_tree(self):
all_children = self.tree.get_children()
for item in all_children:
self.tree.delete(item)
self.tree_items = {}
def clear_dup_tree(self):
all_children = self.dup_tree.get_children()
for item in all_children:
self.dup_tree.delete(item)
self.tree_items = {}
def set_focus(self, event):
event.widget.master.focus_set()
def set_state(self, event):
widget = event.widget
state_name = widget.get()
us = self.state_dict['USA']
canada = self.state_dict['Canada']
mexico = self.state_dict['Mexico']
self.state_name.set(state_name)
if state_name in us:
self.state_abbr.set(us[state_name])
self.country.set('USA')
elif state_name in canada:
self.country.set('Canada')
self.state_abbr.set(canada[state_name])
elif state_name in mexico:
self.country.set('Mexico')
self.state_abbr.set(mexico[state_name])
else:
tm.showerror('set_state', 'State {} Not found'.format(state_name))
self.state_name = None
self.country = None
def cancel(self):
self.clear_entry()
def create_statusbar(self):
self.sb = tk.Frame(self.bottom_frame)
self.sb.grid(row=0, column=0, sticky='nsew')
def save_data(self):
with open(self.filename, 'w') as fo:
json.dump(self.customers, fo)
def update_seq(self, key):
new_seq = None
if key in self.customers:
seq_no = int(self.customers[key]['last_seq'])
new_seq = str(int(seq_no) + 1)
else:
new_seq = '0'
self.customers[key] = {}
self.customers[key]['last_seq'] = new_seq
# self.customers[key]['last_seq'] = str(int(new_seq)+1)
return(new_seq)
def add_customer(self):
# todo - add check to make sure required fields are populated
# todo use new indexing
new_entry = False
lname = self.last_name.get()
fname = self.first_name.get()
key = self.create_key(fname, lname)
seq = self.update_seq(key)
new_customer = self.customers[key][seq] = {}
new_customer['lname'] = lname
new_customer['fname'] = fname
new_customer['seq'] = seq
new_customer['address1'] = self.address1.get()
new_customer['address2'] = self.address2.get()
new_customer['city'] = self.city.get()
new_customer['state_name'] = self.state_name.get()
new_customer['state_abbr'] =self.state_abbr.get()
new_customer['zip'] = self.zipcode.get()
new_customer['country'] = self.country.get()
new_customer['shoesize'] = self.shoe_size.get()
self.save_data()
self.load_tree()
self.clear_entry()
def on_delete(self):
self.parent.destroy()
def main():
root = tk.Tk()
ShoeBot(root)
root.mainloop()
if __name__ == '__main__':
main() MakeStateFile.py
import json
import os
class MakeStateFiles:
def __init__(self):
self.states = {
'USA': {
'Alabama': 'AL',
'Alaska': 'AK',
'Arizona': 'AZ',
'Arkansas': 'AR',
'California': 'CA',
'Colorado': 'CO',
'Connecticut': 'CT',
'Delaware': 'DE',
'District of Columbia': 'DC',
'Florida': 'FL',
'Georgia': 'GA',
'Hawaii': 'HI',
'Idaho': 'ID',
'Illinois': 'IL',
'Indiana': 'IN',
'Iowa': 'IA',
'Kentucky': 'KY',
'Kansas': 'KS',
'Louisiana': 'LA',
'Maine': 'ME',
'Maryland': 'MD',
'Massachusetts': 'MA',
'Michigan': 'MI',
'Mississippi': 'MS',
'Missouri': 'MO',
'Montana': 'MT',
'Nebraska': 'NE',
'Nevada': 'NV',
'New Hampshire': 'NH',
'New Jersey': 'NJ',
'New Mexico': 'NM',
'New York': 'NY',
'North Carolina': 'NC',
'North Dakota': 'ND',
'Ohio': 'OH',
'Oklahoma': 'OK',
'Oregon': 'OR',
'Pennsylvania': 'PA',
'Rhode Island': 'RI',
'South Carolina': 'SC',
'South Dakota': 'SD',
'Tennessee': 'TN',
'Texas': 'TX',
'Utah': 'UT',
'Vermont': 'VT',
'Virginia': 'VA',
'Washington': 'WA',
'West Virginia': 'WV',
'Wisconsin': 'WI',
'Wyoming': 'WY'
},
'Canada': {
'Alberta': 'AB',
'British Columbia': 'BC',
'Manitoba': 'MB',
'New Brunswick': 'NB',
'Newfoundland': 'NF',
'Northwest Territory': 'NT',
'Nova Scotia': 'NS',
'Nunavut': 'NU',
'Ontario': 'ON',
'Prince Edward Island': 'PE',
'Quebec': 'QC',
'Saskatchewan': 'SK',
'Yukon Territory': 'YT'
},
'Mexico': {
'Aguascalientes': 'AG',
'Baja California': 'BJ',
'Baja California Sur': 'BS',
'Campeche': 'CP',
'Chiapas': 'CH',
'Chihuahua': 'CI',
'Coahuila': 'CU',
'Colima': 'CL',
'Distrito Federal': 'DF',
'Durango': 'DG',
'Guanajuato': 'GJ',
'Guerrero': 'GR',
'Hidalgo': 'HG',
'Jalisco': 'JA',
'Mexico': 'EM',
'Michoacan': 'MH',
'Morelos': 'MR',
'Nayarit': 'NA',
'Nuevo': 'Leon NL',
'Oaxaca': 'OA',
'Puebla': 'PU',
'Queretaro': 'QA',
'Quintana': 'Roo QR',
'San Luis Potosi': 'SL',
'Sinaloa': 'SI',
'Sonora': 'SO',
'Tabasco': 'TA',
'Tamaulipas': 'TM',
'Tlaxcala': 'TL',
'Veracruz': 'VZ',
'Yucatan': 'YC',
'Zacatecas': 'ZT',
}
}
self.stup = ('USA','Alabama','Alaska','Arizona','Arkansas','California','Colorado',
'Connecticut','Delaware','District of Columbia', 'Florida','Georgia','Hawaii',
'Idaho','Illinois','Indiana','Iowa','Kentucky','Kansas','Louisiana','Maine',
'Maryland','Massachusetts','Michigan','Mississippi','Missouri','Montana',
'Nebraska','Nevada','New Hampshire','New Jersey','New Mexico','New York',
'North Carolina','North Dakota','Ohio','Oklahoma','Oregon','Pennsylvania',
'Rhode Island','South Carolina','South Dakota','Tennessee','Texas','Utah',
'Vermont','Virginia','Washington','West Virginia','Wisconsin','Wyoming',
' ','Canada', ' ', 'Alberta','British Columbia','Manitoba','New Brunswick',
'Newfoundland','Northwest Territory','Nova Scotia','Nunavut','Ontario',
'Prince Edward Island','Quebec','Saskatchewan','Yukon Territory',' ','Mexico',
' ','Aguascalientes','Baja California', 'Baja California Sur','Campeche',
'Chiapas','Chihuahua','Coahuila','Colima','Distrito Federal', 'Durango',
'Guanajuato','Guerrero','Hidalgo','Jalisco', 'Mexico',' ', 'Michoacan',
'Morelos','Nayarit','Nuevo','Oaxaca','Puebla','Queretaro','Quintana',
'San Luis Potosi','Sinaloa','Sonora', 'Tabasco','Tamaulipas','Tlaxcala',
'Veracruz','Yucatan','Zacatecas')
datapath = os.path.abspath('.')
datapath = '{}\data'.format(datapath)
if not os.path.exists(datapath):
os.makedirs(datapath)
with open('data/States.json', 'w') as state_file:
json.dump(self.states, state_file)
with open('data/StateTuples.json', 'w') as state_tuples:
json.dump(self.stup, state_tuples)
if __name__ == '__main__':
MakeStateFiles()
state_dict = {}
with open('data/States.json', 'r') as f:
state_dict = json.load(f)
# Test dictionary
for key, value in state_dict.items():
for state_name, state_abbr in value.items():
print(f'country: {key}, state_abbr: {state_abbr} state_name: {state_name}')
Posts: 12
Threads: 3
Joined: Jul 2017
Wow, I cannot thank you enough, you obviously put an extreme amount of work into this!
However, I am getting an indentation error for some reason:
Error: Traceback (most recent call last):
File "/Users/me/Desktop/ShoeBot/ShoeBot.py", line 5, in <module>
import MakeStateFile as msf
File "/Users/me/Desktop/ShoeBot/MakeStateFile.py", line 128
datapath = os.path.abspath('.')
^
IndentationError: unexpected indent
|