|
| 1 | +from tkinter import * |
| 2 | +from tkinter import ttk |
| 3 | +import sqlite3 |
| 4 | + |
| 5 | +root = Tk() |
| 6 | +root.title('Python Tkinter Add Functionality To Treeview CRM App') |
| 7 | +root.iconbitmap('Python Tkinter Add Functionality To Treeview CRM App/icons/currency.ico') |
| 8 | +root.geometry("1000x500") |
| 9 | + |
| 10 | +# Add Fake Data |
| 11 | + |
| 12 | +data = [ |
| 13 | + ["John", "Elder", 1, "123 Elder St.", "Las Vegas", "NV", "89137"], |
| 14 | + ["Mary", "Smith", 2, "435 West Lookout", "Chicago", "IL", "60610"], |
| 15 | + ["Tim", "Tanaka", 3, "246 Main St.", "New York", "NY", "12345"], |
| 16 | +] |
| 17 | + |
| 18 | + |
| 19 | +# Do some database stuff |
| 20 | +# Create a database or connect to one that exists |
| 21 | +conn = sqlite3.connect('Python Tkinter Add Functionality To Treeview CRM App/tree_crm.db') |
| 22 | + |
| 23 | +# Create a cursor instance |
| 24 | +c = conn.cursor() |
| 25 | + |
| 26 | +# Create Table |
| 27 | +c.execute("""CREATE TABLE if not exists customers ( |
| 28 | + first_name text, |
| 29 | + last_name text, |
| 30 | + id integer, |
| 31 | + address text, |
| 32 | + city text, |
| 33 | + state text, |
| 34 | + zipcode text) |
| 35 | + """) |
| 36 | +# Add dummy data to table |
| 37 | + |
| 38 | +for record in data: |
| 39 | + c.execute("INSERT INTO customers VALUES (:first_name, :last_name, :id, :address, :city, :state, :zipcode)", |
| 40 | + { |
| 41 | + 'first_name': record[0], |
| 42 | + 'last_name': record[1], |
| 43 | + 'id': record[2], |
| 44 | + 'address': record[3], |
| 45 | + 'city': record[4], |
| 46 | + 'state': record[5], |
| 47 | + 'zipcode': record[6] |
| 48 | + } |
| 49 | + ) |
| 50 | + |
| 51 | + |
| 52 | +# Commit changes |
| 53 | +conn.commit() |
| 54 | + |
| 55 | +# Close our connection |
| 56 | +conn.close() |
| 57 | + |
| 58 | +def query_database(): |
| 59 | + # Create a database or connect to one that exists |
| 60 | + conn = sqlite3.connect('Python Tkinter Add Functionality To Treeview CRM App/tree_crm.db') |
| 61 | + |
| 62 | + # Create a cursor instance |
| 63 | + c = conn.cursor() |
| 64 | + |
| 65 | + c.execute("SELECT * FROM customers") |
| 66 | + records = c.fetchall() |
| 67 | + |
| 68 | + # Add our data to the screen |
| 69 | + global count |
| 70 | + count = 0 |
| 71 | + |
| 72 | + for record in records: |
| 73 | + if count % 2 == 0: |
| 74 | + my_tree.insert(parent='', index='end', iid=count, text='', values=(record[0], record[1], record[2], record[3], record[4], record[5], record[6]), tags=('evenrow',)) |
| 75 | + else: |
| 76 | + my_tree.insert(parent='', index='end', iid=count, text='', values=(record[0], record[1], record[2], record[3], record[4], record[5], record[6]), tags=('oddrow',)) |
| 77 | + # increment counter |
| 78 | + count += 1 |
| 79 | + |
| 80 | + |
| 81 | + # Commit changes |
| 82 | + conn.commit() |
| 83 | + |
| 84 | + # Close our connection |
| 85 | + conn.close() |
| 86 | + |
| 87 | + |
| 88 | + |
| 89 | +# Add Some Style |
| 90 | +style = ttk.Style() |
| 91 | + |
| 92 | +# Pick A Theme |
| 93 | +style.theme_use('default') |
| 94 | + |
| 95 | +# Configure the Treeview Colors |
| 96 | +style.configure("Treeview", |
| 97 | + background="#D3D3D3", |
| 98 | + foreground="black", |
| 99 | + rowheight=25, |
| 100 | + fieldbackground="#D3D3D3") |
| 101 | + |
| 102 | +# Change Selected Color |
| 103 | +style.map('Treeview', |
| 104 | + background=[('selected', "#347083")]) |
| 105 | + |
| 106 | +# Create a Treeview Frame |
| 107 | +tree_frame = Frame(root) |
| 108 | +tree_frame.pack(pady=10) |
| 109 | + |
| 110 | +# Create a Treeview Scrollbar |
| 111 | +tree_scroll = Scrollbar(tree_frame) |
| 112 | +tree_scroll.pack(side=RIGHT, fill=Y) |
| 113 | + |
| 114 | +# Create The Treeview |
| 115 | +my_tree = ttk.Treeview(tree_frame, yscrollcommand=tree_scroll.set, selectmode="extended") |
| 116 | +my_tree.pack() |
| 117 | + |
| 118 | +# Configure the Scrollbar |
| 119 | +tree_scroll.config(command=my_tree.yview) |
| 120 | + |
| 121 | +# Define Our Columns |
| 122 | +my_tree['columns'] = ("First Name", "Last Name", "ID", "Address", "City", "State", "Zipcode") |
| 123 | + |
| 124 | +# Format Our Columns |
| 125 | +my_tree.column("#0", width=0, stretch=NO) |
| 126 | +my_tree.column("First Name", anchor=W, width=140) |
| 127 | +my_tree.column("Last Name", anchor=W, width=140) |
| 128 | +my_tree.column("ID", anchor=CENTER, width=100) |
| 129 | +my_tree.column("Address", anchor=CENTER, width=140) |
| 130 | +my_tree.column("City", anchor=CENTER, width=140) |
| 131 | +my_tree.column("State", anchor=CENTER, width=140) |
| 132 | +my_tree.column("Zipcode", anchor=CENTER, width=140) |
| 133 | + |
| 134 | + |
| 135 | +# Create Headings |
| 136 | +my_tree.heading("#0", text="", anchor=W) |
| 137 | +my_tree.heading("First Name", text="First Name", anchor=W) |
| 138 | +my_tree.heading("Last Name", text="Last Name", anchor=W) |
| 139 | +my_tree.heading("ID", text="ID", anchor=CENTER) |
| 140 | +my_tree.heading("Address", text="Address", anchor=CENTER) |
| 141 | +my_tree.heading("City", text="City", anchor=CENTER) |
| 142 | +my_tree.heading("State", text="State", anchor=CENTER) |
| 143 | +my_tree.heading("Zipcode", text="Zipcode", anchor=CENTER) |
| 144 | + |
| 145 | + |
| 146 | +# Create Striped Row Tags |
| 147 | +my_tree.tag_configure('oddrow', background="white") |
| 148 | +my_tree.tag_configure('evenrow', background="lightblue") |
| 149 | + |
| 150 | + |
| 151 | + |
| 152 | +# Add Record Entry Boxes |
| 153 | +data_frame = LabelFrame(root, text="Record") |
| 154 | +data_frame.pack(fill="x", expand="yes", padx=20) |
| 155 | + |
| 156 | +fn_label = Label(data_frame, text="First Name") |
| 157 | +fn_label.grid(row=0, column=0, padx=10, pady=10) |
| 158 | +fn_entry = Entry(data_frame) |
| 159 | +fn_entry.grid(row=0, column=1, padx=10, pady=10) |
| 160 | + |
| 161 | +ln_label = Label(data_frame, text="Last Name") |
| 162 | +ln_label.grid(row=0, column=2, padx=10, pady=10) |
| 163 | +ln_entry = Entry(data_frame) |
| 164 | +ln_entry.grid(row=0, column=3, padx=10, pady=10) |
| 165 | + |
| 166 | +id_label = Label(data_frame, text="ID") |
| 167 | +id_label.grid(row=0, column=4, padx=10, pady=10) |
| 168 | +id_entry = Entry(data_frame) |
| 169 | +id_entry.grid(row=0, column=5, padx=10, pady=10) |
| 170 | + |
| 171 | +address_label = Label(data_frame, text="Address") |
| 172 | +address_label.grid(row=1, column=0, padx=10, pady=10) |
| 173 | +address_entry = Entry(data_frame) |
| 174 | +address_entry.grid(row=1, column=1, padx=10, pady=10) |
| 175 | + |
| 176 | +city_label = Label(data_frame, text="City") |
| 177 | +city_label.grid(row=1, column=2, padx=10, pady=10) |
| 178 | +city_entry = Entry(data_frame) |
| 179 | +city_entry.grid(row=1, column=3, padx=10, pady=10) |
| 180 | + |
| 181 | +state_label = Label(data_frame, text="State") |
| 182 | +state_label.grid(row=1, column=4, padx=10, pady=10) |
| 183 | +state_entry = Entry(data_frame) |
| 184 | +state_entry.grid(row=1, column=5, padx=10, pady=10) |
| 185 | + |
| 186 | +zipcode_label = Label(data_frame, text="Zipcode") |
| 187 | +zipcode_label.grid(row=1, column=6, padx=10, pady=10) |
| 188 | +zipcode_entry = Entry(data_frame) |
| 189 | +zipcode_entry.grid(row=1, column=7, padx=10, pady=10) |
| 190 | + |
| 191 | +# Move Row Up |
| 192 | +def up(): |
| 193 | + rows = my_tree.selection() |
| 194 | + for row in rows: |
| 195 | + my_tree.move(row, my_tree.parent(row), my_tree.index(row)-1) |
| 196 | + |
| 197 | +# Move Rown Down |
| 198 | +def down(): |
| 199 | + rows = my_tree.selection() |
| 200 | + for row in reversed(rows): |
| 201 | + my_tree.move(row, my_tree.parent(row), my_tree.index(row)+1) |
| 202 | + |
| 203 | +# Remove one record |
| 204 | +def remove_one(): |
| 205 | + x = my_tree.selection()[0] |
| 206 | + my_tree.delete(x) |
| 207 | + |
| 208 | +# Remove Many records |
| 209 | +def remove_many(): |
| 210 | + x = my_tree.selection() |
| 211 | + for record in x: |
| 212 | + my_tree.delete(record) |
| 213 | + |
| 214 | +# Remove all records |
| 215 | +def remove_all(): |
| 216 | + for record in my_tree.get_children(): |
| 217 | + my_tree.delete(record) |
| 218 | + |
| 219 | +# Clear entry boxes |
| 220 | +def clear_entries(): |
| 221 | + # Clear entry boxes |
| 222 | + fn_entry.delete(0, END) |
| 223 | + ln_entry.delete(0, END) |
| 224 | + id_entry.delete(0, END) |
| 225 | + address_entry.delete(0, END) |
| 226 | + city_entry.delete(0, END) |
| 227 | + state_entry.delete(0, END) |
| 228 | + zipcode_entry.delete(0, END) |
| 229 | + |
| 230 | + |
| 231 | +# Select Record |
| 232 | +def select_record(e): |
| 233 | + # Clear entry boxes |
| 234 | + fn_entry.delete(0, END) |
| 235 | + ln_entry.delete(0, END) |
| 236 | + id_entry.delete(0, END) |
| 237 | + address_entry.delete(0, END) |
| 238 | + city_entry.delete(0, END) |
| 239 | + state_entry.delete(0, END) |
| 240 | + zipcode_entry.delete(0, END) |
| 241 | + |
| 242 | + # Grab record Number |
| 243 | + selected = my_tree.focus() |
| 244 | + # Grab record values |
| 245 | + values = my_tree.item(selected, 'values') |
| 246 | + |
| 247 | + # outpus to entry boxes |
| 248 | + fn_entry.insert(0, values[0]) |
| 249 | + ln_entry.insert(0, values[1]) |
| 250 | + id_entry.insert(0, values[2]) |
| 251 | + address_entry.insert(0, values[3]) |
| 252 | + city_entry.insert(0, values[4]) |
| 253 | + state_entry.insert(0, values[5]) |
| 254 | + zipcode_entry.insert(0, values[6]) |
| 255 | + |
| 256 | +# Update record |
| 257 | +def update_record(): |
| 258 | + # Grab the record number |
| 259 | + selected = my_tree.focus() |
| 260 | + # Update record |
| 261 | + my_tree.item(selected, text="", values=(fn_entry.get(), ln_entry.get(), id_entry.get(), address_entry.get(), city_entry.get(), state_entry.get(), zipcode_entry.get(),)) |
| 262 | + |
| 263 | + # Clear entry boxes |
| 264 | + fn_entry.delete(0, END) |
| 265 | + ln_entry.delete(0, END) |
| 266 | + id_entry.delete(0, END) |
| 267 | + address_entry.delete(0, END) |
| 268 | + city_entry.delete(0, END) |
| 269 | + state_entry.delete(0, END) |
| 270 | + zipcode_entry.delete(0, END) |
| 271 | + |
| 272 | + |
| 273 | + |
| 274 | +# Add Buttons |
| 275 | +button_frame = LabelFrame(root, text="Commands") |
| 276 | +button_frame.pack(fill="x", expand="yes", padx=20) |
| 277 | + |
| 278 | +update_button = Button(button_frame, text="Update Record", command=update_record) |
| 279 | +update_button.grid(row=0, column=0, padx=10, pady=10) |
| 280 | + |
| 281 | +add_button = Button(button_frame, text="Add Record") |
| 282 | +add_button.grid(row=0, column=1, padx=10, pady=10) |
| 283 | + |
| 284 | +remove_all_button = Button(button_frame, text="Remove All Records", command=remove_all) |
| 285 | +remove_all_button.grid(row=0, column=2, padx=10, pady=10) |
| 286 | + |
| 287 | +remove_one_button = Button(button_frame, text="Remove One Selected", command=remove_one) |
| 288 | +remove_one_button.grid(row=0, column=3, padx=10, pady=10) |
| 289 | + |
| 290 | +remove_many_button = Button(button_frame, text="Remove Many Selected", command=remove_many) |
| 291 | +remove_many_button.grid(row=0, column=4, padx=10, pady=10) |
| 292 | + |
| 293 | +move_up_button = Button(button_frame, text="Move Up", command=up) |
| 294 | +move_up_button.grid(row=0, column=5, padx=10, pady=10) |
| 295 | + |
| 296 | +move_down_button = Button(button_frame, text="Move Down", command=down) |
| 297 | +move_down_button.grid(row=0, column=6, padx=10, pady=10) |
| 298 | + |
| 299 | +select_record_button = Button(button_frame, text="Clear Entry Boxes", command=clear_entries) |
| 300 | +select_record_button.grid(row=0, column=7, padx=10, pady=10) |
| 301 | + |
| 302 | +# Bind the treeview |
| 303 | +my_tree.bind("<ButtonRelease-1>", select_record) |
| 304 | + |
| 305 | +# Run to pull data from database on start |
| 306 | +query_database() |
| 307 | + |
| 308 | +root.mainloop() |
0 commit comments