├── .gitignore ├── Pipfile ├── README.md ├── db.py ├── part_manager.py └── part_manager_oop.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | build 3 | dist 4 | store.db 5 | part_manager.spec 6 | .vscode 7 | .DS_Store -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | autopep8 = "*" 8 | 9 | [packages] 10 | tkinter = "*" 11 | pyinstaller = "*" 12 | tkmessagebox = "*" 13 | 14 | [requires] 15 | python_version = "3.7" 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Part Manager 2 | 3 | > Python/Tkinter desktop GUI app to manage customer computer parts. This app uses Sqlite3 to store data 4 | 5 | ## Usage 6 | 7 | ```bash 8 | # Install dependencies 9 | pipenv install 10 | 11 | # Run script 12 | python part_manager.py 13 | 14 | 15 | # Compiled with Pyinstaller 16 | 17 | # Windows 18 | pyinstaller --onefile --windowed part_manager.py 19 | 20 | # MacOS 21 | pyinstaller --onefile --add-binary='/System/Library/Frameworks/Tk.framework/Tk':'tk' --add-binary='/System/Library/Frameworks/Tcl.framework/Tcl':'tcl' part_manager.py 22 | ``` 23 | 24 | - Version: 1.0.0 25 | - License: MIT 26 | - Author: Brad Traversy 27 | -------------------------------------------------------------------------------- /db.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | 4 | class Database: 5 | def __init__(self, db): 6 | self.conn = sqlite3.connect(db) 7 | self.cur = self.conn.cursor() 8 | self.cur.execute( 9 | "CREATE TABLE IF NOT EXISTS parts (id INTEGER PRIMARY KEY, part text, customer text, retailer text, price text)") 10 | self.conn.commit() 11 | 12 | def fetch(self): 13 | self.cur.execute("SELECT * FROM parts") 14 | rows = self.cur.fetchall() 15 | return rows 16 | 17 | def insert(self, part, customer, retailer, price): 18 | self.cur.execute("INSERT INTO parts VALUES (NULL, ?, ?, ?, ?)", 19 | (part, customer, retailer, price)) 20 | self.conn.commit() 21 | 22 | def remove(self, id): 23 | self.cur.execute("DELETE FROM parts WHERE id=?", (id,)) 24 | self.conn.commit() 25 | 26 | def update(self, id, part, customer, retailer, price): 27 | self.cur.execute("UPDATE parts SET part = ?, customer = ?, retailer = ?, price = ? WHERE id = ?", 28 | (part, customer, retailer, price, id)) 29 | self.conn.commit() 30 | 31 | def __del__(self): 32 | self.conn.close() 33 | 34 | 35 | # db = Database('store.db') 36 | # db.insert("4GB DDR4 Ram", "John Doe", "Microcenter", "160") 37 | # db.insert("Asus Mobo", "Mike Henry", "Microcenter", "360") 38 | # db.insert("500w PSU", "Karen Johnson", "Newegg", "80") 39 | # db.insert("2GB DDR4 Ram", "Karen Johnson", "Newegg", "70") 40 | # db.insert("24 inch Samsung Monitor", "Sam Smith", "Best Buy", "180") 41 | # db.insert("NVIDIA RTX 2080", "Albert Kingston", "Newegg", "679") 42 | # db.insert("600w Corsair PSU", "Karen Johnson", "Newegg", "130") 43 | -------------------------------------------------------------------------------- /part_manager.py: -------------------------------------------------------------------------------- 1 | from tkinter import * 2 | from tkinter import messagebox 3 | from db import Database 4 | 5 | db = Database('store.db') 6 | 7 | 8 | def populate_list(): 9 | parts_list.delete(0, END) 10 | for row in db.fetch(): 11 | parts_list.insert(END, row) 12 | 13 | 14 | def add_item(): 15 | if part_text.get() == '' or customer_text.get() == '' or retailer_text.get() == '' or price_text.get() == '': 16 | messagebox.showerror('Required Fields', 'Please include all fields') 17 | return 18 | db.insert(part_text.get(), customer_text.get(), 19 | retailer_text.get(), price_text.get()) 20 | parts_list.delete(0, END) 21 | parts_list.insert(END, (part_text.get(), customer_text.get(), 22 | retailer_text.get(), price_text.get())) 23 | clear_text() 24 | populate_list() 25 | 26 | 27 | def select_item(event): 28 | try: 29 | global selected_item 30 | index = parts_list.curselection()[0] 31 | selected_item = parts_list.get(index) 32 | 33 | part_entry.delete(0, END) 34 | part_entry.insert(END, selected_item[1]) 35 | customer_entry.delete(0, END) 36 | customer_entry.insert(END, selected_item[2]) 37 | retailer_entry.delete(0, END) 38 | retailer_entry.insert(END, selected_item[3]) 39 | price_entry.delete(0, END) 40 | price_entry.insert(END, selected_item[4]) 41 | except IndexError: 42 | pass 43 | 44 | 45 | def remove_item(): 46 | db.remove(selected_item[0]) 47 | clear_text() 48 | populate_list() 49 | 50 | 51 | def update_item(): 52 | db.update(selected_item[0], part_text.get(), customer_text.get(), 53 | retailer_text.get(), price_text.get()) 54 | populate_list() 55 | 56 | 57 | def clear_text(): 58 | part_entry.delete(0, END) 59 | customer_entry.delete(0, END) 60 | retailer_entry.delete(0, END) 61 | price_entry.delete(0, END) 62 | 63 | 64 | # Create window object 65 | app = Tk() 66 | 67 | # Part 68 | part_text = StringVar() 69 | part_label = Label(app, text='Part Name', font=('bold', 14), pady=20) 70 | part_label.grid(row=0, column=0, sticky=W) 71 | part_entry = Entry(app, textvariable=part_text) 72 | part_entry.grid(row=0, column=1) 73 | # Customer 74 | customer_text = StringVar() 75 | customer_label = Label(app, text='Customer', font=('bold', 14)) 76 | customer_label.grid(row=0, column=2, sticky=W) 77 | customer_entry = Entry(app, textvariable=customer_text) 78 | customer_entry.grid(row=0, column=3) 79 | # Retailer 80 | retailer_text = StringVar() 81 | retailer_label = Label(app, text='Retailer', font=('bold', 14)) 82 | retailer_label.grid(row=1, column=0, sticky=W) 83 | retailer_entry = Entry(app, textvariable=retailer_text) 84 | retailer_entry.grid(row=1, column=1) 85 | # Price 86 | price_text = StringVar() 87 | price_label = Label(app, text='Price', font=('bold', 14)) 88 | price_label.grid(row=1, column=2, sticky=W) 89 | price_entry = Entry(app, textvariable=price_text) 90 | price_entry.grid(row=1, column=3) 91 | # Parts List (Listbox) 92 | parts_list = Listbox(app, height=8, width=50, border=0) 93 | parts_list.grid(row=3, column=0, columnspan=3, rowspan=6, pady=20, padx=20) 94 | # Create scrollbar 95 | scrollbar = Scrollbar(app) 96 | scrollbar.grid(row=3, column=3) 97 | # Set scroll to listbox 98 | parts_list.configure(yscrollcommand=scrollbar.set) 99 | scrollbar.configure(command=parts_list.yview) 100 | # Bind select 101 | parts_list.bind('<>', select_item) 102 | 103 | # Buttons 104 | add_btn = Button(app, text='Add Part', width=12, command=add_item) 105 | add_btn.grid(row=2, column=0, pady=20) 106 | 107 | remove_btn = Button(app, text='Remove Part', width=12, command=remove_item) 108 | remove_btn.grid(row=2, column=1) 109 | 110 | update_btn = Button(app, text='Update Part', width=12, command=update_item) 111 | update_btn.grid(row=2, column=2) 112 | 113 | clear_btn = Button(app, text='Clear Input', width=12, command=clear_text) 114 | clear_btn.grid(row=2, column=3) 115 | 116 | app.title('Part Manager') 117 | app.geometry('700x350') 118 | 119 | # Populate data 120 | populate_list() 121 | 122 | # Start program 123 | app.mainloop() 124 | 125 | 126 | # To create an executable, install pyinstaller and run 127 | # ''' 128 | # pyinstaller --onefile --add-binary='/System/Library/Frameworks/Tk.framework/Tk':'tk' --add-binary='/System/Library/Frameworks/Tcl.framework/Tcl':'tcl' part_manager.py 129 | # ''' 130 | -------------------------------------------------------------------------------- /part_manager_oop.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from tkinter import messagebox 3 | from db import Database 4 | 5 | # Instanciate databse object 6 | db = Database('store.db') 7 | 8 | # Main Application/GUI class 9 | 10 | 11 | class Application(tk.Frame): 12 | def __init__(self, master): 13 | super().__init__(master) 14 | self.master = master 15 | master.title('Part Manager') 16 | # Width height 17 | master.geometry("700x350") 18 | # Create widgets/grid 19 | self.create_widgets() 20 | # Init selected item var 21 | self.selected_item = 0 22 | # Populate initial list 23 | self.populate_list() 24 | 25 | def create_widgets(self): 26 | # Part 27 | self.part_text = tk.StringVar() 28 | self.part_label = tk.Label( 29 | self.master, text='Part Name', font=('bold', 14), pady=20) 30 | self.part_label.grid(row=0, column=0, sticky=tk.W) 31 | self.part_entry = tk.Entry(self.master, textvariable=self.part_text) 32 | self.part_entry.grid(row=0, column=1) 33 | # Customer 34 | self.customer_text = tk.StringVar() 35 | self.customer_label = tk.Label( 36 | self.master, text='Customer', font=('bold', 14)) 37 | self.customer_label.grid(row=0, column=2, sticky=tk.W) 38 | self.customer_entry = tk.Entry( 39 | self.master, textvariable=self.customer_text) 40 | self.customer_entry.grid(row=0, column=3) 41 | # Retailer 42 | self.retailer_text = tk.StringVar() 43 | self.retailer_label = tk.Label( 44 | self.master, text='Retailer', font=('bold', 14)) 45 | self.retailer_label.grid(row=1, column=0, sticky=tk.W) 46 | self.retailer_entry = tk.Entry( 47 | self.master, textvariable=self.retailer_text) 48 | self.retailer_entry.grid(row=1, column=1) 49 | # Price 50 | self.price_text = tk.StringVar() 51 | self.price_label = tk.Label( 52 | self.master, text='Price', font=('bold', 14)) 53 | self.price_label.grid(row=1, column=2, sticky=tk.W) 54 | self.price_entry = tk.Entry(self.master, textvariable=self.price_text) 55 | self.price_entry.grid(row=1, column=3) 56 | 57 | # Parts list (listbox) 58 | self.parts_list = tk.Listbox(self.master, height=8, width=50, border=0) 59 | self.parts_list.grid(row=3, column=0, columnspan=3, 60 | rowspan=6, pady=20, padx=20) 61 | # Create scrollbar 62 | self.scrollbar = tk.Scrollbar(self.master) 63 | self.scrollbar.grid(row=3, column=3) 64 | # Set scrollbar to parts 65 | self.parts_list.configure(yscrollcommand=self.scrollbar.set) 66 | self.scrollbar.configure(command=self.parts_list.yview) 67 | 68 | # Bind select 69 | self.parts_list.bind('<>', self.select_item) 70 | 71 | # Buttons 72 | self.add_btn = tk.Button( 73 | self.master, text="Add Part", width=12, command=self.add_item) 74 | self.add_btn.grid(row=2, column=0, pady=20) 75 | 76 | self.remove_btn = tk.Button( 77 | self.master, text="Remove Part", width=12, command=self.remove_item) 78 | self.remove_btn.grid(row=2, column=1) 79 | 80 | self.update_btn = tk.Button( 81 | self.master, text="Update Part", width=12, command=self.update_item) 82 | self.update_btn.grid(row=2, column=2) 83 | 84 | self.exit_btn = tk.Button( 85 | self.master, text="Clear Input", width=12, command=self.clear_text) 86 | self.exit_btn.grid(row=2, column=3) 87 | 88 | def populate_list(self): 89 | # Delete items before update. So when you keep pressing it doesnt keep getting (show example by calling this twice) 90 | self.parts_list.delete(0, tk.END) 91 | # Loop through records 92 | for row in db.fetch(): 93 | # Insert into list 94 | self.parts_list.insert(tk.END, row) 95 | 96 | # Add new item 97 | def add_item(self): 98 | if self.part_text.get() == '' or self.customer_text.get() == '' or self.retailer_text.get() == '' or self.price_text.get() == '': 99 | messagebox.showerror( 100 | "Required Fields", "Please include all fields") 101 | return 102 | print(self.part_text.get()) 103 | # Insert into DB 104 | db.insert(self.part_text.get(), self.customer_text.get(), 105 | self.retailer_text.get(), self.price_text.get()) 106 | # Clear list 107 | self.parts_list.delete(0, tk.END) 108 | # Insert into list 109 | self.parts_list.insert(tk.END, (self.part_text.get(), self.customer_text.get( 110 | ), self.retailer_text.get(), self.price_text.get())) 111 | self.clear_text() 112 | self.populate_list() 113 | 114 | # Runs when item is selected 115 | def select_item(self, event): 116 | # # Create global selected item to use in other functions 117 | # global self.selected_item 118 | try: 119 | # Get index 120 | index = self.parts_list.curselection()[0] 121 | # Get selected item 122 | self.selected_item = self.parts_list.get(index) 123 | # print(selected_item) # Print tuple 124 | 125 | # Add text to entries 126 | self.part_entry.delete(0, tk.END) 127 | self.part_entry.insert(tk.END, self.selected_item[1]) 128 | self.customer_entry.delete(0, tk.END) 129 | self.customer_entry.insert(tk.END, self.selected_item[2]) 130 | self.retailer_entry.delete(0, tk.END) 131 | self.retailer_entry.insert(tk.END, self.selected_item[3]) 132 | self.price_entry.delete(0, tk.END) 133 | self.price_entry.insert(tk.END, self.selected_item[4]) 134 | except IndexError: 135 | pass 136 | 137 | # Remove item 138 | def remove_item(self): 139 | db.remove(self.selected_item[0]) 140 | self.clear_text() 141 | self.populate_list() 142 | 143 | # Update item 144 | def update_item(self): 145 | db.update(self.selected_item[0], self.part_text.get( 146 | ), self.customer_text.get(), self.retailer_text.get(), self.price_text.get()) 147 | self.populate_list() 148 | 149 | # Clear all text fields 150 | def clear_text(self): 151 | self.part_entry.delete(0, tk.END) 152 | self.customer_entry.delete(0, tk.END) 153 | self.retailer_entry.delete(0, tk.END) 154 | self.price_entry.delete(0, tk.END) 155 | 156 | 157 | root = tk.Tk() 158 | app = Application(master=root) 159 | app.mainloop() 160 | --------------------------------------------------------------------------------