Skip to content

Commit bcb61de

Browse files
committed
Added all project files.
1 parent d803b13 commit bcb61de

File tree

3 files changed

+391
-0
lines changed

3 files changed

+391
-0
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,9 @@ dmypy.json
127127

128128
# Pyre type checker
129129
.pyre/
130+
131+
# Mac OS dir file.
132+
.DS_Store
133+
134+
# Personal application config file.
135+
GBC_Config.txt

GBC_Instructions.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Welcome to David Wisnosky's GradeBook Calculator
2+
3+
A few tips to get started:
4+
1) You can refer to these instructions at any time by clicking the "Instructions" button.
5+
2) The "Add Class" button will add a class. This class will consist of: a class name you may enter, ten entries for category names, ten entries for category values, and ten entries for you average in a specific category.
6+
(Note: all numerical entries should be done in the form of a decimal, i.e. a 90% would be .90)
7+
3) You may have a maximum of nine classes.
8+
4) The "Remove Class" button will remove the most recently created class. (You must have have one or more classes at the time of use)
9+
5) The "Calculate Average" button will calculate your average in each class and display the result underneath the class cell. (You must have have one or more classes at the time of use)
10+
(For any cells that you do not wish to use leave them blank.)
11+
Enjoy!

Gradebook_Calculator.py

Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
1+
# Imports library for GUI and Message box.
2+
import tkinter as TK
3+
from tkinter import messagebox
4+
5+
# Creates the class for the GUI, allowing all of its objects and attributes to be acted upon properly.
6+
class Gradebook_Calculator:
7+
def __init__(self, root):
8+
self.root = root
9+
10+
# Checks if the user has used the program before and skips the intro and instructions.
11+
def Returning_User_Check(self):
12+
13+
# Reads config file to check user status.
14+
self.config = open('GBC_Config.txt', 'a+')
15+
self.config.seek(0)
16+
self.returning_user = self.config.readline()
17+
18+
# First time user is sent through whole path and returning users are sent to main page.
19+
if self.returning_user != 'Returning':
20+
self.returning = False
21+
self.config.write('Returning')
22+
self.config.close()
23+
self.Get_Started()
24+
25+
elif self.returning_user == 'Returning':
26+
self.returning = True
27+
self.Create_Gradebook()
28+
29+
# Creates the first window.
30+
def Get_Started(self):
31+
32+
# Moves to second page
33+
self.get_started = TK.Button(self.root, text='Get Started', command=self.Intro)
34+
self.get_started.pack()
35+
36+
# Creates the instructions page.
37+
def Intro(self):
38+
39+
# Removes the first page.
40+
self.get_started.destroy()
41+
42+
# Auto maximizes the window.
43+
self.root.state('zoomed')
44+
45+
# Pulls up the instructions.
46+
self.gradebook_instructions_intro = open('GBC_Instructions.txt', 'r')
47+
self.temp_GB_I_I = self.gradebook_instructions_intro.read()
48+
self.gradebook_instructions_intro.close()
49+
50+
self.introduction = TK.Label(self.root, text=self.temp_GB_I_I)
51+
self.introduction.pack()
52+
53+
# Moves to the next page.
54+
self.start_working = TK.Button(self.root, text='Start', command=self.Create_Gradebook)
55+
self.start_working.pack()
56+
57+
self.config = open('GBC_Config.txt', 'w')
58+
self.temp_config = self.config.write('Returning')
59+
60+
''' Creates the space for the grade book, establishes the buttons for: pulling up reference instructions, adding a class cell, removing a class cell,
61+
and calculating grades. This also allows the grade book to adapt to any screen size, and creates most of the variables to be used later.'''
62+
def Create_Gradebook(self):
63+
64+
# Removes the previous page if user is first time.
65+
if self.returning == False:
66+
self.introduction.destroy()
67+
self.start_working.destroy()
68+
69+
if self.returning == True:
70+
self.root.state('zoomed')
71+
72+
# Creates function buttons.
73+
self.instructions_button = TK.Button(self.root, text='Instructions', command=self.Instructions)
74+
self.instructions_button.grid(row=0, column=0)
75+
76+
self.add_class_button = TK.Button(self.root, text='Add Class', command=self.Add_Class)
77+
self.add_class_button.grid(row=0, column=1)
78+
79+
self.remove_class_button = TK.Button(self.root, text='Remove Class', command=self.Remove_Class)
80+
self.remove_class_button.grid(row=0, column=2)
81+
82+
self.calculate_button = TK.Button(self.root, text='Calculate Average', command=self.Calculate)
83+
self.calculate_button.grid(row=0, column=3)
84+
85+
# Adapts GUI for any screen.
86+
for c in range(13):
87+
root.grid_columnconfigure(c, weight=1)
88+
for r in range(45):
89+
root.grid_rowconfigure(r, weight=1)
90+
91+
# Variables for the one per class cell.
92+
self.class_name_labels = list()
93+
self.names_of_classes = list()
94+
self.category_name_labels = list()
95+
self.category_value_labels = list()
96+
self.category_average_labels = list()
97+
self.column_spacers = list()
98+
99+
# Variables for the ten per class cell.
100+
self.names_of_categories = list()
101+
self.values_of_categories = list()
102+
self.category_grades = list()
103+
self.row_spacers = list()
104+
105+
# Counts the number of classes and the cells within the class.
106+
self.class_cell_counter = 0
107+
self.cell_counter = 0
108+
109+
# Places the widgets in the proper location by tracking current row and column.
110+
self.grid_tracker_row = 0
111+
self.grid_tracker_column = 0
112+
113+
# Is used to see if a calculation has been performed or not.
114+
self.calculated = False
115+
self.all_calculated = False
116+
117+
# Variables for calculating and displaying averages.
118+
self.class_averages = list()
119+
self.averages_of_classes = list()
120+
121+
# Pulls up the instructions in a separate window for reference.
122+
def Instructions(self):
123+
124+
self.gradebook_instructions = open('GBC_Instructions.txt', 'r')
125+
self.temp_GB_I = self.gradebook_instructions.read()
126+
self.gradebook_instructions.close()
127+
128+
self.instructions_window = TK.Toplevel()
129+
self.instructions_window.title('Instructions')
130+
131+
self.instructions = TK.Label(self.instructions_window, text=self.temp_GB_I)
132+
self.instructions.pack()
133+
134+
self.close_instructions = TK.Button(self.instructions_window, text='Dismiss', command=self.instructions_window.destroy)
135+
self.close_instructions.pack()
136+
137+
self.instructions_window.mainloop()
138+
139+
140+
'''Adds a class(A class includes a name label with one name entry, a category name label with up to ten category name entries, a category value label
141+
with up to ten category value entries, a category average label with ten category average entries. Also included are blank column, and row labels to
142+
space and organize the grade book.)'''
143+
def Add_Class(self):
144+
145+
# Tells user about the class limit.
146+
if self.class_cell_counter == 9:
147+
self.class_limit_max = TK.messagebox.showinfo('', 'You may only have nine classes.')
148+
149+
else:
150+
151+
# Creates the one per class widgets.
152+
self.class_name_label = TK.Label(self.root, text='Class Name')
153+
self.class_name_label.grid(row=(1 + self.grid_tracker_row), column=(2 + self.grid_tracker_column))
154+
self.class_name_labels.append(self.class_name_label)
155+
156+
self.name_of_class = TK.Entry(self.root)
157+
self.name_of_class.grid(row=(2 + self.grid_tracker_row), column=(2 + self.grid_tracker_column))
158+
self.names_of_classes.append(self.name_of_class)
159+
160+
self.category_name_label = TK.Label(self.root, text='Category Name')
161+
self.category_name_label.grid(row=(3 + self.grid_tracker_row), column=(1 + self.grid_tracker_column))
162+
self.category_name_labels.append(self.category_name_label)
163+
164+
self.category_value_label = TK.Label(self.root, text='Category Value')
165+
self.category_value_label.grid(row=(3 + self.grid_tracker_row), column=(2 + self.grid_tracker_column))
166+
self.category_value_labels.append(self.category_value_label)
167+
168+
self.category_average_label = TK.Label(self.root, text='Category Average')
169+
self.category_average_label.grid(row=(3 + self.grid_tracker_row), column=(3 + self.grid_tracker_column))
170+
self.category_average_labels.append(self.category_average_label)
171+
172+
173+
self.column_spacer = TK.Label(self.root, text=' ')
174+
self.column_spacer.grid(row=(3 + self.grid_tracker_row), column=(4 + self.grid_tracker_column))
175+
self.column_spacers.append(self.column_spacer)
176+
177+
# Creates the ten per class widgets.
178+
for z in range(10):
179+
180+
self.name_of_category = TK.Entry(self.root)
181+
self.name_of_category.grid(row=(4 + z + self.grid_tracker_row), column=(1 + self.grid_tracker_column))
182+
self.names_of_categories.append(self.name_of_category)
183+
184+
self.value_of_category = TK.Entry(self.root)
185+
self.value_of_category.grid(row=(4 + z + self.grid_tracker_row), column=(2 + self.grid_tracker_column))
186+
self.values_of_categories.append(self.value_of_category)
187+
188+
self.category_grade = TK.Entry(self.root)
189+
self.category_grade.grid(row=(4 + z + self.grid_tracker_row), column=(3 + self.grid_tracker_column))
190+
self.category_grades.append(self.category_grade)
191+
192+
self.row_spacer = TK.Label(self.root, text='\n')
193+
self.row_spacer.grid(row=(15 + self.grid_tracker_row), column=(1 + self.grid_tracker_column))
194+
self.row_spacers.append(self.row_spacer)
195+
196+
# Tracks amount of classes and amount of cells or widgets.
197+
self.class_cell_counter += 1
198+
self.cell_counter += 10
199+
200+
# Tracks cell locations.
201+
self.grid_tracker_column += 4
202+
if self.class_cell_counter == 3 or self.class_cell_counter == 6:
203+
self.grid_tracker_row += 17
204+
self.grid_tracker_column = 0
205+
206+
# This variable is used to prevent logic errors when calculating classes after adding.
207+
self.class_status = 'Add'
208+
209+
# Prevents logic errors when classes are added and removed after a calculation and before another.
210+
if self.calculated == True:
211+
self.all_calculated = False
212+
213+
# Removes an entire class along with the average label if it exists.
214+
def Remove_Class(self):
215+
216+
# Tells user to add a class.
217+
if self.class_cell_counter < 1:
218+
self.class_limit_min = TK.messagebox.showinfo('', 'Please add a class first.')
219+
220+
else:
221+
222+
# Removes the one per class widgets.
223+
self.class_name_labels[self.class_cell_counter - 1].destroy()
224+
del self.class_name_labels[self.class_cell_counter - 1]
225+
226+
self.names_of_classes[self.class_cell_counter - 1].destroy()
227+
del self.names_of_classes[self.class_cell_counter - 1]
228+
229+
self.category_name_labels[self.class_cell_counter - 1].destroy()
230+
del self.category_name_labels[self.class_cell_counter - 1]
231+
232+
self.category_value_labels[self.class_cell_counter - 1].destroy()
233+
del self.category_value_labels[self.class_cell_counter - 1]
234+
235+
self.category_average_labels[self.class_cell_counter - 1].destroy()
236+
del self.category_average_labels[self.class_cell_counter - 1]
237+
238+
self.column_spacers[self.class_cell_counter - 1].destroy()
239+
del self.column_spacers[self.class_cell_counter - 1]
240+
241+
# Removes the ten per class widgets.
242+
for z in range(10):
243+
244+
self.names_of_categories[self.cell_counter - z - 1].destroy()
245+
del self.names_of_categories[self.cell_counter - z - 1]
246+
247+
self.values_of_categories[self.cell_counter - z - 1].destroy()
248+
del self.values_of_categories[self.cell_counter - z - 1]
249+
250+
self.category_grades[self.cell_counter - z - 1].destroy()
251+
del self.category_grades[self.cell_counter - z - 1]
252+
253+
self.row_spacers[self.cell_counter - z - 1].destroy()
254+
del self.row_spacers[self.cell_counter - z - 1]
255+
256+
# Tracks the amount of classes and cells or widgets.
257+
self.class_cell_counter -= 1
258+
self.cell_counter -= 10
259+
260+
# Tracks cell locations.
261+
self.grid_tracker_column -= 4
262+
if self.class_cell_counter == 2 or self.class_cell_counter == 5:
263+
self.grid_tracker_row -= 17
264+
self.grid_tracker_column = 8
265+
266+
# Removes the average label if it exists and prevents indexing errors if a calculation has been preformed before classes are removed.
267+
if self.calculated == True:
268+
if self.all_calculated == True:
269+
if self.class_status == 'Add':
270+
self.averages_of_classes[self.temp_class_cell_counter - 1].destroy()
271+
del self.averages_of_classes[self.temp_class_cell_counter - 1]
272+
self.temp_class_cell_counter -= 1
273+
if self.class_status == 'Remove':
274+
self.averages_of_classes[self.class_cell_counter].destroy()
275+
del self.averages_of_classes[self.class_cell_counter]
276+
self.temp_class_cell_counter -= 1
277+
278+
# Resets the calculated variable if all classes are removed.
279+
if self.class_cell_counter == 0:
280+
self.calculated = False
281+
282+
# This variable is used to prevent logic errors when calculating classes after removing.
283+
self.class_status = 'Remove'
284+
285+
# Calculates the average
286+
def Calculate(self):
287+
288+
# Stores average calculations.
289+
self.class_averages.clear()
290+
291+
# Gets proper values for calculations without disturbing the tracking of the cells.
292+
self.average_cell_counter = 0
293+
294+
# Tracks the location for placing the average labels without disturbing the placement tracker for other cells.
295+
self.average_grid_tracker_row = 0
296+
self.average_grid_tracker_column = 0
297+
298+
# Informs user a class must be added.
299+
if self.class_cell_counter < 1:
300+
self.need_class = TK.messagebox.showinfo('', 'Please add at least one class.')
301+
302+
# Calculates the average and then adds the average label to the display.
303+
if self.class_cell_counter >= 1:
304+
305+
# Prevents the labels from overlapping on multiple calculations by delete the current widgets.
306+
if self.calculated == True:
307+
308+
# Prevents a list indexing error if a class is added after a calculations.
309+
if self.class_status == 'Add':
310+
for d in range(self.temp_class_cell_counter):
311+
self.averages_of_classes[0].destroy()
312+
del self.averages_of_classes[0]
313+
314+
# Prevents a list indexing error if a class is removed after a calculations.
315+
if self.class_status == 'Remove':
316+
for e in range(self.temp_class_cell_counter):
317+
self.averages_of_classes[0].destroy()
318+
del self.averages_of_classes[0]
319+
320+
# Denotes that a calculation has been preformed.
321+
self.calculated = True
322+
self.all_calculated = True
323+
324+
# Calculates the grade, and creates the label for all class cells that exist at the time.
325+
for n in range(self.class_cell_counter):
326+
self.category_averages = list()
327+
328+
# Gets the values from the category value and category average entries if the entry is filled if not the entry is skipped.
329+
for m in range(10):
330+
if self.values_of_categories[m + self.average_cell_counter].get() == '' or self.category_grades[m + self.average_cell_counter].get() == '':
331+
self.category_averages.append(0)
332+
else:
333+
self.category_averages.append(float(self.values_of_categories[m + self.average_cell_counter].get())*float(self.category_grades[m + self.average_cell_counter].get()))
334+
335+
# Converts the grade average to a percent.
336+
self.class_averages.append((sum(self.category_averages)*100))
337+
338+
# Creates the label displaying the averages.
339+
self.average_of_class = TK.Label(self.root, text='Average for {} {} %'.format(self.names_of_classes[n].get(), self.class_averages[n]))
340+
self.average_of_class.grid(row=(15 + self.average_grid_tracker_row), column=(2 + self.average_grid_tracker_column))
341+
self.averages_of_classes.append(self.average_of_class)
342+
343+
# Tracks the cell location for calculations.
344+
self.average_cell_counter += 10
345+
346+
# Tracks the average label locations.
347+
self.average_grid_tracker_column += 4
348+
if n == 2 or n == 5:
349+
self.average_grid_tracker_row += 17
350+
self.average_grid_tracker_column = 0
351+
352+
# Stores the current amount of classes at the time of calculation to prevent list indexing errors.
353+
self.temp_class_cell_counter = self.class_cell_counter
354+
355+
# Method to start the GUI.
356+
def Run(self):
357+
358+
# Calls the first method to allow the user to begin acting within the program.
359+
self.Returning_User_Check()
360+
361+
# Keeps the GUI running.
362+
self.root.mainloop()
363+
364+
# Main (Where program begins.)
365+
if __name__ =='__main__':
366+
367+
# GUI function, title.
368+
root = TK.Tk()
369+
root.title('Gradebook Calculator')
370+
371+
# Pulls the Gradebook_Calculator class and begin (runs) it.
372+
GBC = Gradebook_Calculator(root)
373+
GBC.Run()
374+

0 commit comments

Comments
 (0)