|
| 1 | +"""---------------------------------------------------------------------------------------------------------------------------------------- |
| 2 | + ///////////////////////////////////////////////////// |
| 3 | + / **FRONT-END** / |
| 4 | + / **DOCUMENTATION** / |
| 5 | + / Martin Batista - python progrmr 07/24/2018 / |
| 6 | + ///////////////////////////////////////////////////// |
| 7 | +FRONT-END: tKinter GUI |
| 8 | +BACK-END: Sqlite3 |
| 9 | +*FEATURES/REQUIREMENTS* |
| 10 | +
|
| 11 | +A program that stores this book information: |
| 12 | +Title, Author |
| 13 | +Year, ISBN |
| 14 | +
|
| 15 | +User can: |
| 16 | +.Show list of current record (listbox widget) |
| 17 | +.Search current entry |
| 18 | +.Add Entry |
| 19 | +.Update Selected |
| 20 | +.Delete Selected |
| 21 | +.Close |
| 22 | +
|
| 23 | +Will be using grid method for the GUI. |
| 24 | +
|
| 25 | +Future scaling, revisioning: |
| 26 | +Can create another function that clears the entry fields. |
| 27 | +---------------------------------------------------------------------------------------------------------------------------------------------""" |
| 28 | +from tkinter import * |
| 29 | +import backend # functions |
| 30 | + |
| 31 | + |
| 32 | +# WRAPPER FUNCTIONS THAT CONNECT THE BUTTONS TO THE BACKEND FUNCTIONS... |
| 33 | + |
| 34 | +# this function is called by simply selecting an entry or tuple from the listbox object...its not triggered by a button like the other wrapper functions... |
| 35 | +# list1.bind('<<ListboxSelect>>',get_selected_row)... |
| 36 | +def get_selected_row(event): # note: the curselection() method returns tuples... |
| 37 | + try: # prevents IndexError exception from being thrown when user clicks an empty listbox... |
| 38 | + global selected_tuple # now selected_tuple is a global variable recognized throughout the code... |
| 39 | + index=list1.curselection()[0] # this trick will grab the first item with index 0 per tuple...otherwise the curselection() output will return tuples like this: (2,) (3,) etc... |
| 40 | + selected_tuple=list1.get(index) # returns tuple at selected index... # ^ index 0 of this single tuple... |
| 41 | + # return selected_tuple |
| 42 | + # print(event) |
| 43 | + # print(type(event)) |
| 44 | + # the following code will delete or purge the entry fields and will insert(), distribute the selected tuple into the respective entry fields thus displaying it to the user... |
| 45 | + e1.delete(0,END) |
| 46 | + e1.insert(END,selected_tuple[1]) # title has an index of [1], the id is the primary key and it has an index of [0]... |
| 47 | + e2.delete(0,END) |
| 48 | + e2.insert(END,selected_tuple[2]) # author has an index of [2] |
| 49 | + e3.delete(0,END) |
| 50 | + e3.insert(END,selected_tuple[3]) # year has an index of [3] |
| 51 | + e4.delete(0,END) |
| 52 | + e4.insert(END,selected_tuple[4]) # isbn has an index of [4] |
| 53 | + except IndexError: |
| 54 | + pass |
| 55 | + |
| 56 | +#print(END) |
| 57 | + |
| 58 | + |
| 59 | +# b1 button...text="View All" |
| 60 | +def view_command(): |
| 61 | + list1.delete(0,END) # prevents program from inserting duplicate entries over and over everytime you press View All button... |
| 62 | + for row in backend.view(): # view() method returns a list of tuples... |
| 63 | + list1.insert(END,row) # insert list of tuples into listbox object... |
| 64 | + |
| 65 | +# b2=Button(window,text="Search Entry" |
| 66 | +def search_command(): |
| 67 | + list1.delete(0,END) |
| 68 | + for row in backend.search(title_text.get(),author_text.get(),year_text.get(),isbn_text.get()): # stringVar objects getting strings from user entry... |
| 69 | + list1.insert(END,row) # insert the found strings into the listbox object... |
| 70 | + |
| 71 | +# b3=Button(window,text="Add Entry" |
| 72 | +def add_command(): |
| 73 | + backend.insert(title_text.get(),author_text.get(),year_text.get(),isbn_text.get()) # insert new entry into database... |
| 74 | + list1.delete(0,END) # first clear the list... |
| 75 | + list1.insert(END,(title_text.get(),author_text.get(),year_text.get(),isbn_text.get())) # then display the new entry to show the user's input... |
| 76 | + # note the tuple being used so that the new entry display's as a row and not multiple lines... |
| 77 | + |
| 78 | +# b5=Button(window,text="Delete selected" |
| 79 | +def delete_command(): # passing global variable selected_tuple[0]... |
| 80 | + backend.delete(selected_tuple[0]) # will delete the selected_tuple at index[0] for that single tuple returned... |
| 81 | + # now you won't get the TypeError: get_selected_row() missing 1 required positional argument: 'event' cuz you are not passing the event arugment to delete_command()... |
| 82 | + |
| 83 | + |
| 84 | +def update_command(): # getting the updated data from the entry fields and updating the database...notice the get() methods... |
| 85 | + backend.update(selected_tuple[0],title_text.get(),author_text.get(),year_text.get(),isbn_text.get()) # will delete the selected_tuple at index[0] for that single tuple returned... |
| 86 | + print(selected_tuple[0],selected_tuple[1],selected_tuple[2],selected_tuple[3],selected_tuple[4]) |
| 87 | + |
| 88 | + |
| 89 | + |
| 90 | + |
| 91 | +window=Tk() # all code goes after here... Tk() not tk() ---> NameError: name 'tk' is not defined |
| 92 | + |
| 93 | +window.wm_title("BookStore App - powered by Python") |
| 94 | + |
| 95 | + |
| 96 | +# label objects and their x y coordinates... |
| 97 | +l0=Label(window,text="Martin Batista Python Prgrmr - Guavadream Media Software") |
| 98 | +l0.grid(row=0,column=0) |
| 99 | + |
| 100 | +l1=Label(window,text="Title") |
| 101 | +l1.grid(row=1,column=0) |
| 102 | + |
| 103 | +l2=Label(window,text="Author") |
| 104 | +l2.grid(row=1,column=2) |
| 105 | + |
| 106 | +l3=Label(window,text="Year") |
| 107 | +l3.grid(row=2,column=0) |
| 108 | + |
| 109 | +l4=Label(window,text="ISBN") |
| 110 | +l4.grid(row=2,column=2) |
| 111 | + |
| 112 | +# entry objects and their x y coordinates... |
| 113 | +title_text=StringVar() # object for user input... |
| 114 | +e1=Entry(window,textvariable=title_text) |
| 115 | +e1.grid(row=1,column=1) |
| 116 | + |
| 117 | +author_text=StringVar() # object for user input... |
| 118 | +e2=Entry(window,textvariable=author_text) |
| 119 | +e2.grid(row=1,column=3) |
| 120 | + |
| 121 | +year_text=StringVar() # object for user input... |
| 122 | +e3=Entry(window,textvariable=year_text) |
| 123 | +e3.grid(row=2,column=1) |
| 124 | + |
| 125 | +isbn_text=StringVar() # object for user input... |
| 126 | +e4=Entry(window,textvariable=isbn_text) |
| 127 | +e4.grid(row=2,column=3) |
| 128 | + |
| 129 | + |
| 130 | +# list box object and its x y coordinates... |
| 131 | +list1=Listbox(window, height=6,width=35) |
| 132 | +list1.grid(row=3,column=0,rowspan=6,columnspan=2) |
| 133 | + |
| 134 | +# scrollnbar object and its x y coordinates... |
| 135 | +sb1=Scrollbar(window) |
| 136 | +sb1.grid(row=3,column=2,rowspan=6) |
| 137 | + |
| 138 | +list1.configure(yscrollcommand=sb1.set) # tell the list object about the scrollbar object... |
| 139 | +sb1.configure(command=list1.yview) # tell the scrollbar object about the list object... |
| 140 | + |
| 141 | +# associating or binding the wrapper function: get_selected_row to the listbox object...so by selecting an item in the listbox, you call the get_selected_row() functon... |
| 142 | +list1.bind('<<ListboxSelect>>',get_selected_row) # bind() method takes 2 arguments... an event type and a function that you want to bind to the event type... |
| 143 | + |
| 144 | + |
| 145 | +# button objects and their x y coordinates...triggering their associated wrapper functions... |
| 146 | +b1=Button(window,text="View All", width=12, command=view_command) # python would normally run or call this function if passed like this...view_command() with parentheses... |
| 147 | +b1.grid(row=3,column=3) |
| 148 | + |
| 149 | +b2=Button(window,text="Search Entry", width=12, command=search_command) # this is why we don't use parentheses...Python/tkinter then knows to wait for button to call it... |
| 150 | +b2.grid(row=4,column=3) |
| 151 | + |
| 152 | +b3=Button(window,text="Add Entry", width=12, command=add_command) |
| 153 | +b3.grid(row=5,column=3) |
| 154 | + |
| 155 | +b4=Button(window,text="Update selected", width=12, command=update_command) |
| 156 | +b4.grid(row=6,column=3) |
| 157 | + |
| 158 | +b5=Button(window,text="Delete selected", width=12, command=delete_command) |
| 159 | +b5.grid(row=7,column=3) |
| 160 | + |
| 161 | +b6=Button(window,text="Close", width=12, command=window.destroy) # closes the app... |
| 162 | +b6.grid(row=8,column=3) |
| 163 | + |
| 164 | +window.mainloop() # all code goes before here... |
| 165 | + |
| 166 | + |
| 167 | +#------------------------------------------------------------------------------** Found Bug **------------------------------------------------------------------------------------ |
| 168 | +"""----------------------------------- This occurs when calling the get_selected_row() function by clicking into the listbox object...------------------------------------------- |
| 169 | +DEBUGGING OUTPUT: |
| 170 | +Exception in Tkinter callback |
| 171 | +Traceback (most recent call last): |
| 172 | + File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/tkinter/__init__.py", line 1702, in __call__ |
| 173 | + return self.func(*args) |
| 174 | + File "frontend.py", line 35, in get_selected_row |
| 175 | + index=list1.curselection()[0] # this trick will grab the first item with index 0 per tuple...otherwise the curselection() output will return tuples like this: (2,) (3,) etc... |
| 176 | +IndexError: tuple index out of range |
| 177 | +
|
| 178 | +must write an IndexError Try block... |
| 179 | +
|
| 180 | +** To make an executable file run this ** This creates a single executable file...otherwise you get a bunch of support files that |
| 181 | +are actually good for troubleshooting... include the --onefile parameter... |
| 182 | +pyinstaller --onefile frontend.py |
| 183 | +This command generates a terminal command line in the background of your GUI...to avoid this type in this other parameter called --windowed |
| 184 | +pyinstaller --onefile --windowed frontend.py |
| 185 | +
|
| 186 | +
|
| 187 | +
|
| 188 | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------""" |
0 commit comments