· 9 years ago · Mar 31, 2017, 10:44 AM
1# NEA
2# Andrew Howell Candidate No. 0082
3# St. John Payne School Centre No. 16331
4
5runProgram = True
6
7##### Importing Python Modules needed for program #####
8
9# Defensive programming - catching exceptions in code where python modules are not present
10try:
11 import tkinter as tk
12 from tkinter import messagebox
13 from tkinter import *
14except:
15 print("Python's Tkinter module not installed, Program cannot run")
16 runProgram = False
17
18try:
19 import pickle
20except:
21 messagebox.showinfo("Error","Python's Pickle module not installed, Program cannot run")
22 runProgram = False
23
24try:
25 import datetime
26except:
27 messagebox.showinfo("Error","Python's Datetime module not installed, Program cannot run")
28 runProgram = False
29
30try:
31 import math
32except:
33 messagebox.showinfo("Error","Python's Datetime module not installed, Program cannot run")
34 runProgram = False
35
36try:
37 import random
38except:
39 messagebox.showinfo("Error","Python's Random module not installed, Program cannot run")
40 runProgram = False
41
42try:
43 import passlib
44 from passlib.hash import pbkdf2_sha256
45except:
46 messagebox.showinfo("Error","Python's Passlib module not installed, Program cannot run")
47 runProgram = False
48
49#######################################################
50
51
52
53
54
55##### Constant Declaration #####
56
57# Using passlib's hashing algorithm, password is securely encrypted
58HASHEDADMINPASSWORD = "$pbkdf2-sha256$29000$COH8X8sZQ6j1PkeoFUIIQQ$64MnDDlriVWgZGjjXEHP/HnlweMr/OkbAmAvgUGYDoA"
59
60ADMIN = ["Admin", HASHEDADMINPASSWORD] # Admin details
61
62LARGEFONT = ("Verdana", 22) # Font format for titles on each page
63MEDIUMFONT = ("Verdana", 16)
64LABELFONT = ("Verdana", 13)
65SMALLFONT = ("Verdana", 11)
66
67# Dimensions of the Tkinter window
68WIDTH = 800
69HEIGHT = 600
70
71FILENAME = "NEADatabase.dat" # Constant database name
72
73################################
74
75
76
77
78
79##### File Handling #####
80
81#Username Format: USERNAMES[Username] = [Password, Score, LastSession]
82USERNAMES = {} # Dictionary where student details will be stored whilst the program runs
83try:
84 try:
85 USERNAMES = pickle.load(open(FILENAME, "rb")) # Retrieves dictionary of user details stored in database
86 except:
87 pickle.dump({},open(FILENAME, "wb")) # If database not present in directory, create file
88except EOFError:
89 pass
90
91def saveUsers(): # Writes the current dictionary of user details to the database
92 pickle.dump(USERNAMES, open(FILENAME, "wb"))
93
94#########################
95
96
97
98
99
100##### Mathematical Operational Functions #####
101
102def Modulus(a):
103 if a < 0:
104 a = -a
105 return a
106
107def mergeSort(alist):
108 if len(alist) > 1:
109 mid = len(alist)//2
110 lefthalf = alist[:mid]
111 righthalf = alist[mid:]
112
113 mergeSort(lefthalf)
114 mergeSort(righthalf)
115
116 leftHalfPosition = 0
117 rightHalfPosition = 0
118 originalListPosition = 0
119 while leftHalfPosition < len(lefthalf) and rightHalfPosition < len(righthalf):
120 if lefthalf[leftHalfPosition] < righthalf[rightHalfPosition]:
121 alist[originalListPosition] = lefthalf[leftHalfPosition]
122 leftHalfPosition += 1
123 else:
124 alist[originalListPosition] = righthalf[rightHalfPosition]
125 rightHalfPosition += 1
126 originalListPosition += 1
127
128 while leftHalfPosition < len(lefthalf):
129 alist[originalListPosition] = lefthalf[leftHalfPosition]
130 leftHalfPosition += 1
131 originalListPosition += 1
132
133 while rightHalfPosition < len(righthalf):
134 alist[originalListPosition]=righthalf[rightHalfPosition]
135 rightHalfPosition += 1
136 originalListPosition += 1
137
138 return alist
139
140def getCurrentDate(): # Returns array of current day, month and year
141 day = datetime.date.today().day
142 month = datetime.date.today().month
143 year = datetime.date.today().year
144
145 date = [day, month, year]
146
147 return date
148
149##############################################
150
151
152
153
154##### SUVAT Equation Solving Algorithm #####
155
156class SUVAT():
157
158 def __init__(self,s,u,v,a,t,shortAnswer):
159
160 # Passes parameters from user as attributes
161 self.s = s
162 self.u = u
163 self.v = v
164 self.a = a
165 self.t = t
166 self.sA = shortAnswer # Boolean - determines whether object returns worded answer or just numeric answer
167
168 try:
169 def initiate(self):
170 if self.s == "x":
171 return self.SUVAT1()
172 elif self.u == "x":
173 return self.SUVAT2()
174 elif self.v == "x":
175 return self.SUVAT3()
176 elif self.a == "x":
177 return self.SUVAT4()
178 elif self.t == "x":
179 return self.SUVAT5()
180 except:
181 messagebox.showinfo("Error","Invalid details inputted, try again", icon = "warning")
182
183 def SUVAT1(self): # v = u + at (s = 'X')
184
185 if self.u == "a":
186 self.u = float(self.v) - float(self.a)*float(self.t) # Converts string parameters given by user to a float value
187 if self.sA: # If the user wants a short answer -> using Checker not Solver
188 return [self.u,0] # Some calculations return two values so a 2 element array is returned
189 else:
190 return("Initial Velocity is {0:.2f} ms^-1".format(self.u))
191
192 elif self.v == "a":
193 self.v = float(self.u) + float(self.a)*float(self.t)
194 if self.sA:
195 return [self.v,0]
196 else:
197 return("Final Velocity is {0:.2f} ms^-1".format(self.v))
198
199 elif self.a == "a":
200 if float(self.t) == 0:
201 return "zeroDivision error"
202 else:
203 self.a = (float(self.v) - float(self.u))/float(self.t)
204 if self.sA:
205 return [self.a,0]
206 else:
207 return("Acceleration is {0:.2f} ms^-2".format(self.a))
208
209 elif self.t == "a":
210 if float(self.a) == 0:
211 return "zeroDivision error" # Calculation would include a division by zero which creates an error and so
212 # validation will inform the user that the question cannot include a division by zero
213 else:
214 self.t = (float(self.v) - float(self.u))/float(self.a)
215 if self.sA:
216 return [self.t,0]
217 else:
218 return("Time Taken is {0:.2f} s".format(self.t))
219
220 def SUVAT2(self): # s = vt - 0.5at^2 (u = 'X')
221
222 if self.s == "a":
223 self.s = float(self.v)*float(self.t) - 0.5*float(self.a)*float(self.t)**2
224 if self.sA:
225 return [self.s,0]
226 else:
227 return("Displacement is {0:.2f} m".format(self.s))
228
229 elif self.v == "a":
230 if float(self.t) == 0:
231 return "zeroDivision error"
232 else:
233 self.v = float(self.s)/float(self.t) + 0.5*float(self.a)*float(self.t)
234 if self.sA:
235 return [self.v,0]
236 else:
237 return("Final Velocity is {0:.2f} ms^-1".format(self.v))
238
239 elif self.a == "a":
240 if float(self.t) == 0:
241 return "zeroDivision error"
242 else:
243 self.a = (float(self.v)*float(self.t) - float(self.s))/(0.5*float(self.t)**2)
244 if self.sA:
245 return [self.a,0]
246 else:
247 return("Acceleration is {0:.2f} ms^-2".format(self.a))
248
249 elif self.t == "a":
250 if float(self.a) == 0:
251 return "zeroDivision error"
252 else:
253 x = float(self.v)**2 - 2*float(self.a)*float(self.s)
254 x = Modulus(x)
255 x = math.sqrt(x)
256 t1 = ((float(self.v) + (x))/float(self.a))
257 t2 = ((float(self.v) - (x))/float(self.a))
258 if self.sA:
259 return [t1,t2] # Two values of t
260 else:
261 return("Time Taken is {0:.2f} s and {1:.2f} s".format(t1, t2))
262
263 def SUVAT3(self): # s = ut + 0.5at^2 (v = 'X')
264
265 if self.s == "a":
266 self.s = float(self.u)*float(self.t) + 0.5*float(self.a)*float(self.t)**2
267 if self.sA:
268 return [self.s,0]
269 else:
270 return("Displacement is {0:.2f} m".format(self.s))
271
272 elif self.u == "a":
273 if float(self.t) == 0:
274 return "zeroDivision error"
275 else:
276 self.u = float(self.s)/float(self.t) - 0.5*float(self.a)*float(self.t)
277 if self.sA:
278 return [self.u,0]
279 else:
280 return("Initial Velocity is {0:.2f} ms^-1".format(self.u))
281
282 elif self.a == "a":
283 if float(self.t) == 0:
284 return "zeroDivision error"
285 else:
286 self.a = (float(self.s) - float(self.u)*float(self.t))/(0.5*float(self.t)**2)
287 if self.sA:
288 return [self.a,0]
289 else:
290 return("Acceleration is {0:.2f} ms^-2".format(self.a))
291
292 elif self.t == "a":
293 if float(self.a) == 0:
294 return "zeroDivision error"
295 else: # Using quadratic equation - returns two values of t
296 x = float(self.u)**2 + 2*float(self.a)*float(self.s)
297 x = Modulus(x)
298 x = math.sqrt(x)
299 t1 = ((-float(self.u) + (x))/float(self.a))
300 t2 = ((-float(self.u) - (x))/float(self.a))
301 if self.sA:
302 return [t1,t2]
303 else:
304 return("Time Taken is {0:.2f} s and {1:.2f} s".format(t1, t2))
305
306 def SUVAT4(self): # s = 0.5(u + v)t (a = 'X')
307
308 if self.s == "a":
309 self.s = 0.5*(float(self.u) + float(self.v))*float(self.t)
310 if self.sA:
311 return [self.s,0]
312 else:
313 return("Displacement is {0:.2f} m".format(self.s))
314
315 elif self.u == "a":
316 if float(self.t) == 0:
317 return "zeroDivision error"
318 else:
319 self.u = (2*float(self.s))/float(self.t) - float(self.v)
320 if self.sA:
321 return [self.u,0]
322 else:
323 return("Initial Velocity is {0:.2f} ms^-1".format(float(self.u)))
324
325 elif self.v == "a":
326 if float(self.t) == 0:
327 return "zeroDivision error"
328 else:
329 self.v = (2*float(self.s))/float(self.t) - float(self.u)
330 if self.sA:
331 return [self.v,0]
332 else:
333 return("Final Velocity is {0:.2f} ms^-1".format(self.v))
334
335 elif self.t == "a":
336 if (float(self.u) + float(self.v)) == 0:
337 return "zeroDivision error"
338 else:
339 self.t = (2*float(self.s))/(float(self.u) + float(self.v))
340 if self.sA:
341 return [self.t,0]
342 else:
343 return("Time Taken is {0:.2f} s".format(self.t))
344
345 def SUVAT5(self): # v^2 = u^2 + 2as (t = 'X')
346
347 if self.s == "a":
348 if float(self.a) == 0:
349 return "zeroDivision error"
350 else:
351 self.s = (float(self.v)**2 - float(self.u)**2)/2*float(self.a)
352 if self.sA:
353 return [self.s,0]
354 else:
355 return("Displacement is {0:.2f} m".format(self.s))
356
357 elif self.u == "a":
358 uSquared = float(self.v)**2 - 2*float(self.a)*float(self.s)
359 self.u = math.sqrt(Modulus(uSquared)) # If self.u is negative,
360 # square rooting it will cause
361 # an error, so we square root the modulus
362 if self.sA:
363 return [self.u,0]
364 else:
365 return("Initial Velocity is {0:.2f} ms^-1".format(self.u))
366
367 elif self.v == "a":
368 vSquared = float(self.u)**2 + 2*float(self.a)*float(self.s)
369 self.v = math.sqrt(Modulus(vSquared))
370 if self.sA:
371 return [self.v,0]
372 else:
373 return("Final Velocity is {0:.2f} ms^-1".format(self.v))
374
375 elif self.a == "a":
376 if float(self.s) == 0:
377 return "zeroDivision error"
378 else:
379 self.a = (float(self.v)**2 - float(self.u)**2)/2*float(self.s)
380 if self.sA:
381 return [self.a,0]
382 else:
383 return("Acceleration is {0:.2f} ms^-2".format(self.a))
384
385############################################
386
387
388
389
390
391##### GUI Classes #####
392
393# Parent class which hosts the structure of the GUI interface, subsequent pages are frames displayed on this GUI interface
394class GUI(tk.Tk):
395
396 def __init__(self, *args, **kwargs): # Allows a variable amount of keyworded and non-keyworded arguements to be passed into the object
397
398 self.activeUser = "" # Stores the Username of a current user
399
400 tk.Tk.__init__(self, *args, **kwargs)
401
402 tk.Tk.iconbitmap(self, default="NEALogo.ico") # Displays telescope icon to be displayed in left-hand corner of the GUI window
403 tk.Tk.wm_title(self, "Physics Learning Aid") # Displays on the header of th GUI window
404
405 container = tk.Frame(self) # Container holds all elements of the frames and the toolbar
406 container.pack(side="top", fill="both", expand = True)
407 container.grid_rowconfigure(0, weight=1) # Weight attribute added to allow the rows and colunmns to display properly
408 container.grid_columnconfigure(0, weight=1)
409
410 menubar = tk.Menu(container) # Creates the toolbar where students can easily access different pages
411 self.filemenu = tk.Menu(menubar, tearoff=0)
412 self.filemenu.add_command(label="Home", state="disable", command = lambda: self.show_frame(homePage)) # Pages disabled until a user logs in
413 self.filemenu.add_command(label="1: Forces", state="disable", command = lambda: self.show_frame(forcesPage))
414 self.filemenu.add_command(label="2: Time Graphs", state="disable", command = lambda: self.show_frame(timeGraphsPage))
415 self.filemenu.add_command(label="3. SUVAT Revision", state="disable", command = lambda: self.show_frame(SUVATRevisionPage))
416 self.filemenu.add_command(label="Account", command = lambda: self.show_frame(accountPage))
417
418 helpmenu = tk.Menu(self.filemenu, tearoff=0) # Dropdown menu
419 helpmenu.add_command(label="General Help", command=self.helpme)
420 helpmenu.add_command(label="Application Help", command=self.helpme)
421 helpmenu.add_command(label="SUVAT Solver Help", command=self.helpme)
422 self.filemenu.add_cascade(label="Help", menu=helpmenu)
423
424 tk.Tk.config(self, menu=self.filemenu)
425
426 self.frames = {}
427
428 # Creates each individual page as an object is instanciated from the page classes
429 for page in (startPage, accountPage, changePasswordPage, loginPage, signupPage, adminLoginPage, adminPage, homePage, forcesPage, ScalarsVectorsPage, AdditionVectorsCalculationPage,
430 AdditionVectorsScaleDrawingPage, ResolutionOfVectorsPage, InclinedPlaneVectorsPage, VectorsInEquilibriumPage, timeGraphsPage, GradientsPage, AreaUnderCurvePage, BouncingBallPage,
431 SUVATRevisionPage, SUVATCheckerPage, SUVATSolverPage):
432
433 frame = page(container, self)
434
435 self.frames[page] = frame
436
437 frame.grid(row=0, column=0, sticky="nsew")
438
439 self.centreScreen(WIDTH, HEIGHT)
440
441 def helpme(self):
442 helpList = ["Please seek help from your teacher", "Ask your teacher for help, they're right behind you!", "Help Bot Open Hours -> 11:59PM SUN - 00:00AM MON\nPlease come back then", "Tough, help yourself, I'M BUSY",
443 "I'm in the Bahamas on holiday right now\n\nLEAVE\n\nME\n\nALONE"]
444 helpChoice = random.randrange(len(helpList))
445 helpComment = helpList[helpChoice-1]
446 messagebox.showinfo("Help Bot","Hi, you have requested help\n\n{}".format(helpComment), icon="info")
447
448 def enableWidgets(self):
449 self.filemenu.entryconfig("Home", state="normal")
450 self.filemenu.entryconfig("1: Forces", state="normal")
451 self.filemenu.entryconfig("2: Time Graphs", state="normal")
452 self.filemenu.entryconfig("3. SUVAT Revision", state="normal")
453
454 def disableWidgets(self):
455 self.filemenu.entryconfig("Home", state="disable")
456 self.filemenu.entryconfig("1: Forces", state="disable")
457 self.filemenu.entryconfig("2: Time Graphs", state="disable")
458 self.filemenu.entryconfig("3. SUVAT Revision", state="disable")
459
460 def addScore(self, score):
461 if window.activeUser != "Admin" and window.activeUser != "":
462 USERNAMES[self.activeUser][1] += score
463
464 def centreScreen(self, w, h): # Uses screen dimensions to centre the GUI window
465
466 ws = self.winfo_screenwidth()
467 hs = self.winfo_screenheight()
468
469 # Finds the top left coordinate that the GUI will be in order to be centered
470 x = (ws / 2) - (w / 2)
471 y = (hs / 2) - (w / 2)
472
473 # Align window with the top left coordinate
474 self.geometry("%dx%d+%d+%d" % (w, h, x, y)) # takes parameters as 'wxh+x+y'
475
476 self.show_frame(startPage)
477
478 def logout(self):
479 if self.activeUser != "" and self.activeUser != ADMIN[0]:
480 date = getCurrentDate()
481 USERNAMES[self.activeUser][2] = date
482 self.activeUser = ""
483 self.disableWidgets()
484 messagebox.showinfo("Logged out", "You have been logged out successfully")
485 saveUsers()
486 self.show_frame(startPage)
487
488 def show_frame(self, cont):
489
490 frame = self.frames[cont]
491 frame.tkraise() # When called it raises the given page to the top of the GUI
492
493### Start of Page Classes ###
494
495class startPage(tk.Frame):
496
497 def __init__(self, parent, controller):
498
499 tk.Frame.__init__(self, parent)
500 self.title = tk.Label(self, text="Start Page", font=LARGEFONT)
501 self.title.pack(side="top", fill="x", pady=30)
502
503 self.welcomeMsg = tk.Label(self, text = "Welcome to the Physics Learning Aid!")
504 self.label1 = tk.Label(self, text = "Are you a")
505 self.student = tk.Button(self, text = "Student", command=lambda: controller.show_frame(accountPage),height=2,width=20)
506 self.label2 = tk.Label(self, text = "or ")
507 self.teacher = tk.Button(self, text = "Teacher", command=lambda: controller.show_frame(adminLoginPage),height=2,width=20)
508
509 self.welcomeMsg.pack(side="top", fill="x", padx=5, pady=20)
510 self.label1.pack(side="top", fill="x", pady=5)
511 self.student.pack(side="top", pady=5)
512 self.label2.pack(side="top", fill="x", pady=5)
513 self.teacher.pack(side="top", pady=5)
514
515class accountPage(tk.Frame):
516
517 def __init__(self, parent, controller):
518
519 tk.Frame.__init__(self, parent)
520 self.title = tk.Label(self, text="Account Page", font=LARGEFONT)
521 self.title.pack(side="top", fill="x", pady=30)
522
523 self.login = tk.Button(self, text = "Existing User - Log in", command=lambda: controller.show_frame(loginPage),height=2,width=20)
524 self.signUp = tk.Button(self, text = "New User - Sign Up", command=lambda: controller.show_frame(signupPage),height=2,width=20)
525 self.logoutButton = tk.Button(self, text = "Log out", command=lambda: window.logout())
526 self.selectButton = tk.Button(self,text = "Score", command=lambda: showScore())
527 self.changePasswordButton = tk.Button(self, text = "Change Password", command=lambda: changePassword())
528
529 self.login.pack(side="top", fill="x", padx=300, pady=20)
530 self.signUp.pack(side="top", fill="x", padx=300, pady=5)
531 self.selectButton.pack(side="top", pady=20)
532 self.logoutButton.pack(side="bottom", pady=10)
533 self.changePasswordButton.pack(side="bottom")
534
535 # Displays the user's details, their username, current score and the date they last were on the program
536 def showScore():
537 if window.activeUser != "" and window.activeUser != "Admin":
538 score = USERNAMES[window.activeUser][1]
539 messagebox.showinfo("Your Details","Username : {0}\n\nScore : {1}".format(window.activeUser,score), icon="info")
540 else:
541 messagebox.showinfo("Error","Cannot display score\n\nYou are not logged in as a student", icon="warning")
542
543 def changePassword():
544 if window.activeUser != "" or window.activeUser != "Admin":
545 controller.show_frame(changePasswordPage)
546 else:
547 messagebox.showinfo("Error","Please login before trying to change your password", icon="warning")
548 self.login.focus()
549
550class changePasswordPage(tk.Frame):
551
552 def __init__(self, parent, controller):
553
554 tk.Frame.__init__(self, parent)
555 self.title = tk.Label(self, text="Change Password", font=LARGEFONT)
556 self.title.pack(padx=10, pady=10)
557
558 self.originalPasswordText = tk.Label(self, text = "Original Password:")
559 self.originalPasswordInput = tk.Entry(self, justify="center", show="*", width=30)
560
561 self.newPasswordText = tk.Label(self, text = "New Password:")
562 self.newPasswordInput = tk.Entry(self, justify="center", show="*", width=30)
563
564 self.confirmPasswordText = tk.Label(self, text = "Confirm Password:")
565 self.confirmPasswordInput = tk.Entry(self, justify="center", show="*", width=30)
566
567 self.changePasswordButton = tk.Button(self,text = "Change Password", command=lambda: changePassword())
568
569 self.originalPasswordText.pack(side="top", fill="x", padx=20, pady=5)
570 self.originalPasswordInput.pack(side="top")
571 self.originalPasswordInput.focus()
572
573 self.newPasswordText.pack(side="top", fill="x", padx=20, pady=5)
574 self.newPasswordInput.pack(side="top")
575
576 self.confirmPasswordText.pack(side="top", fill="x", padx=20, pady=5)
577 self.confirmPasswordInput.pack(side="top")
578
579 self.changePasswordButton.pack(side="top", fill="y", padx=20, pady=10)
580
581 def changePassword():
582
583 if self.originalPasswordInput.get() == USERNAMES[window.activeUser][0]:
584 if self.newPasswordInput.get() == self.confirmPasswordInput.get():
585 USERNAMES[window.activeUser][0] = self.newPasswordInput.get()
586 messagebox.showinfo("Password Changed","Your password has been changed successfully!", icon="info")
587 controller.show_frame(accountPage)
588 else:
589 messagebox.showinfo("Error","Your new and confirmation password do not match\nPlease try again", icon="warning")
590 self.newPasswordInput.delete(0,"end")
591 self.confirmPasswordInput.delete(0,"end")
592 self.newPasswordInput.focus()
593 else:
594 messagebox.showinfo("Error","Incorrect original password\nPlease try again", icon="warning")
595 self.originalPasswordInput.delete(0,"end")
596 self.newPasswordInput.delete(0,"end")
597 self.confirmPasswordInput.delete(0,"end")
598 self.newPasswordInput.focus()
599
600class loginPage(tk.Frame):
601
602 def __init__(self, parent, controller):
603
604 tk.Frame.__init__(self, parent)
605 self.title = tk.Label(self, text="Login", font=LARGEFONT)
606 self.title.pack(side="top", fill="x", pady=30)
607
608 # User details entry boxes
609 self.usernameText = tk.Label(self, text = "Username:")
610 self.usernameInput = tk.Entry(self, justify="center", width=30)
611 self.passwordText = tk.Label(self, text = "Password:")
612 self.passwordInput = tk.Entry(self, show="*", justify="center", width=30)
613
614 self.loginButton = tk.Button(self,text = "Login", command=lambda: login())
615
616 self.usernameText.pack(side="top", fill="x", padx=20, pady=5)
617 self.usernameInput.pack(side="top", pady=5)
618 self.usernameInput.focus()
619 self.passwordText.pack(side="top", fill="x", padx=20, pady=5)
620 self.passwordInput.pack(side="top", pady=5)
621 self.loginButton.pack(side="top", pady="10")
622
623 def login(): # Validation ensuring username exists, and that the password given matches the saved password
624 if self.usernameInput.get() in USERNAMES:
625 if self.passwordInput.get() == USERNAMES[self.usernameInput.get()][0]:
626 window.activeUser = self.usernameInput.get()
627 messagebox.showinfo("Login Successful","Welcome back {0}".format(self.usernameInput.get()), icon = "info")
628 self.usernameInput.delete(0,"end") # Deletes value in entry box as it will not be removed automatically when a new frame is raised
629 self.passwordInput.delete(0,"end")
630 controller.show_frame(homePage)
631 window.enableWidgets()
632 else:
633 self.passwordInput.delete(0,"end")
634 messagebox.showinfo("Login Failed", "Incorrect Password", icon = "warning")
635 self.passwordInput.focus()
636 else:
637 self.usernameInput.delete(0,"end")
638 self.passwordInput.delete(0,"end")
639 messagebox.showinfo("Login Failed", "Username not found, please try again if you are an existing user\nIf not, register by clicking on the account tab at the top", icon = "warning")
640 self.usernameInput.focus()
641
642class signupPage(tk.Frame):
643
644 def __init__(self, parent, controller):
645
646 tk.Frame.__init__(self, parent)
647 title = tk.Label(self, text="Sign Up", font=LARGEFONT)
648 title.pack(padx=10, pady=10)
649
650 self.firstNameText = tk.Label(self, text = "First Name:")
651 self.firstNameInput = tk.Entry(self, justify="center", width=30)
652
653 self.secondNameText = tk.Label(self, text = "Second Name:")
654 self.secondNameInput = tk.Entry(self, justify="center", width=30)
655
656 self.yearOfEntryText = tk.Label(self, text = "Year of Entry to SJP (YYYY):")
657 self.yearOfEntryInput = tk.Entry(self, justify="center", width=30)
658
659 self.passwordText = tk.Label(self, text = "New Password:")
660 self.passwordInput = tk.Entry(self, show="*", justify="center", width=30)
661
662 self.passwordText2 = tk.Label(self, text = "Confirm Password:")
663 self.passwordInput2 = tk.Entry(self, show="*", justify="center", width=30)
664
665 self.signupButton = tk.Button(self,text = "Register", command=lambda: signup())
666
667 # Pack the elements onto the GUI window
668 self.firstNameText.pack(side="top", fill="x", padx=20, pady=5)
669 self.firstNameInput.pack(side="top")
670 self.firstNameInput.focus()
671
672 self.secondNameText.pack(side="top", fill="x", padx=20, pady=5)
673 self.secondNameInput.pack(side="top")
674
675 self.yearOfEntryText.pack(side="top", fill="x", padx=20, pady=5)
676 self.yearOfEntryInput.pack(side="top")
677
678 self.passwordText.pack(side="top", fill="x", padx=20, pady=5)
679 self.passwordInput.pack(side="top")
680
681 self.passwordText2.pack(side="top", fill="x", padx=20, pady=5)
682 self.passwordInput2.pack(side="top")
683
684 self.signupButton.pack(side="top", fill="y", padx=20, pady=10)
685
686 def signup():
687
688 # Create local variables that are easier to manipulate inside the function
689 firstName = self.firstNameInput.get()
690 secondName = self.secondNameInput.get()
691 yearOfEntry = self.yearOfEntryInput.get()
692 password = self.passwordInput.get()
693
694 if firstName == "" or secondName == "" or yearOfEntry == "" or password == "":
695 messagebox.showinfo("Error!","Please do not leave any fields blank", icon = "warning")
696 else:
697 if yearOfEntry.isdigit() == False:
698 messagebox.showinfo("Invalid Year of Entry", "Please enter a valid 4 digit year", icon = "warning")
699 self.yearOfEntryInput.delete(0,"end")
700 self.yearOfEntryInput.focus()
701
702 else:
703 if self.passwordInput.get() != self.passwordInput2.get():
704 messagebox.showinfo("Passwords do not match", "The passwords you entered did not match\n\nPlease ensure they match", icon = "warning")
705 self.passwordInput.delete(0,"end")
706 self.passwordInput2.delete(0,"end")
707 self.passwordInput.focus()
708
709 else:
710 newUsername = yearOfEntry[2:] + secondName.lower() + firstName[0].lower() # Creates a username, compiled from the student's year of entry, their surname and the first initial of their forename
711 if newUsername in USERNAMES:
712 messagebox.showinfo("Error!","That user already exists\n\nIf someone in your year shares your name, add a space on the end of your surname", icon = "warning")
713 self.firstNameInput.delete(0,"end")
714 self.secondNameInput.delete(0,"end")
715 self.yearOfEntryInput.delete(0,"end")
716 self.passwordInput.delete(0,"end")
717 self.passwordInput2.delete(0,"end")
718 self.firstNameInput.focus() # Resets the form and focuses the keyboard onto the first entry field
719 else:
720 revisionScore = 0 # Each students starts with a score of 0, this will be added to and subtracted from when they perform tasks on the program
721 lastSession = [] # This will hold the date which the student last logged out on, it is overwritten when the user logs out of the program
722 USERNAMES[newUsername] = [password, revisionScore, lastSession] # Creates entry in the USERNAMES dictionary holding all the usernames, will later be pickled to the database when logging out
723
724 window.activeUser = newUsername # Assigns the active user as the newly registered user
725
726 messagebox.showinfo("Registered","Welcome {0}".format(newUsername), icon = "info")
727
728 self.firstNameInput.delete(0,"end")
729 self.secondNameInput.delete(0,"end")
730 self.yearOfEntryInput.delete(0,"end")
731 self.passwordInput.delete(0,"end")
732 self.passwordInput2.delete(0,"end")
733 window.enableWidgets()
734 controller.show_frame(homePage)
735
736class adminLoginPage(tk.Frame):
737
738 def __init__(self, parent, controller):
739
740 tk.Frame.__init__(self, parent)
741 self.title = tk.Label(self, text="Admin Login Page", font=LARGEFONT)
742 self.title.pack(side="top", fill="x", pady=30)
743
744 self.usernameText = tk.Label(self, text = "Admin Username:")
745 self.usernameInput = tk.Entry(self, justify="center", width=30)
746 self.passwordText = tk.Label(self, text = "Admin Password:")
747 self.passwordInput = tk.Entry(self, show="*", justify="center", width=30)
748
749 self.loginButton = tk.Button(self,text = "Login", command=lambda: adminLogin())
750
751 self.usernameText.pack(side="top", fill="x", padx=20, pady=5)
752 self.usernameInput.pack(side="top", pady=5)
753 self.usernameInput.focus()
754 self.passwordText.pack(side="top", fill="x", padx=20, pady=5)
755 self.passwordInput.pack(side="top", pady=5)
756 self.loginButton.pack(side="top", pady="10")
757
758 def adminLogin():
759 if self.usernameInput.get() == ADMIN[0]:
760 if pbkdf2_sha256.verify(self.passwordInput.get(), ADMIN[1]):
761 window.activeUser = self.usernameInput.get()
762 messagebox.showinfo("Login Successful","Continue to Admin Page".format(self.usernameInput.get()), icon = "info")
763 self.usernameInput.delete(0,"end")
764 self.passwordInput.delete(0,"end")
765 controller.show_frame(adminPage)
766 window.enableWidgets()
767 else:
768 self.usernameInput.delete(0,"end")
769 self.passwordInput.delete(0,"end")
770 messagebox.showinfo("Login Failed", "Incorrect details", icon = "warning")
771 self.usernameInput.focus()
772 else:
773 self.usernameInput.delete(0,"end")
774 self.passwordInput.delete(0,"end")
775 messagebox.showinfo("Login Failed", "Incorrect details", icon = "warning")
776 self.usernameInput.focus()
777
778class adminPage(tk.Frame):
779
780 def __init__(self, parent, controller):
781
782 tk.Frame.__init__(self, parent)
783 self.title = tk.Label(self, text="Admin Page", font=LARGEFONT)
784 self.title.pack(padx=10, pady=10)
785
786 username = StringVar()
787 username.set("Usernames")
788
789 self.usernameText = tk.Label(self, text = "Select students to review details:")
790 self.usernamesList = list(USERNAMES) # Creates an array, holding all the key values from the dictionary USERNAMES
791 self.dropdown = OptionMenu(self, username, *self.usernamesList)
792
793 self.updateButton = tk.Button(self,text = "Update and Sort (Alphabetically)", command=lambda: updateUsernames())
794 self.selectButton = tk.Button(self,text = "Search", command=lambda: searchUsername())
795
796 self.usernameText.pack(side="top", padx=20, pady=5)
797 self.dropdown.pack(side="top", padx=20, pady=5)
798 self.updateButton.pack(side="top", pady=10)
799 self.selectButton.pack(side="top")
800
801 # Displays the user's details, their username, current score and the date they last were on the program
802 def searchUsername():
803 if username.get() in USERNAMES:
804 score = USERNAMES[username.get()][1]
805 lastSession = USERNAMES[username.get()][2]
806 messagebox.showinfo("User Details","Username : {0}\n\nScore : {1}\n\nLast Session : {2}/{3}/{4}".format(username.get(),score,lastSession[0],lastSession[1],lastSession[2]))
807 username.set("Usernames")
808
809 # Updates the usernames list, sorting them into alphabetical order of their username, allowing the teacher to easily search for a student
810 def updateUsernames():
811 username.set("Usernames")
812 self.dropdown["menu"].delete(0,"end")
813
814 self.usernamesList = list(USERNAMES) # Takes into account any new users
815 self.usernamesList = mergeSort(self.usernamesList) # Calls global function to merge sort the list of
816 for each in self.usernamesList:
817 self.dropdown["menu"].add_command(label=each, command=tk._setit(username, each))
818
819class homePage(tk.Frame):
820
821 def __init__(self, parent, controller):
822
823 tk.Frame.__init__(self, parent)
824 self.title = tk.Label(self, text="Learning Options Page", font=LARGEFONT)
825 self.title.pack(padx=10, pady=10)
826
827 self.welcomeMsg = tk.Label(self, text = "Welcome to the Physics Learning Aid!")
828 self.forcesButton = tk.Button(self, text = "1. Forces", command=lambda: controller.show_frame(forcesPage),height=2,width=20)
829 self.label1 = tk.Label(self, text = "or ")
830 self.timeGraphsButton = tk.Button(self, text = "2. Time Graphs", command=lambda: controller.show_frame(timeGraphsPage),height=2,width=20)
831 self.label2 = tk.Label(self, text = "or ")
832 self.SUVATRevisionButton = tk.Button(self, text = "3. SUVAT Revision", command=lambda: controller.show_frame(SUVATRevisionPage),height=2,width=20)
833
834 self.welcomeMsg.pack(side="top", fill="x", padx=5, pady=20)
835 self.forcesButton.pack(side="top", pady=5)
836 self.label1.pack(side="top", fill="x", pady=5)
837 self.timeGraphsButton.pack(side="top", pady=5)
838 self.label2.pack(side="top", fill="x", pady=5)
839 self.SUVATRevisionButton.pack(side="top", pady=5)
840
841# Forces Pages #
842
843class forcesPage(tk.Frame):
844
845 def __init__(self, parent, controller):
846
847 tk.Frame.__init__(self, parent)
848 self.title = tk.Label(self, text="Forces Page", font=LARGEFONT)
849 self.title.pack(padx=10, pady=10)
850
851 self.label = tk.Label(self, text = "Forces Topics:", font = MEDIUMFONT)
852 self.ScalarsVectorsButton = tk.Button(self, text = "Scalars and Vectors", command=lambda: controller.show_frame(ScalarsVectorsPage))
853 self.AdditionVectorsCalculationButton = tk.Button(self, text = "Addition of Vectors - Calculation", command=lambda: controller.show_frame(AdditionVectorsCalculationPage))
854 self.AdditionVectorsScaleDrawingButton = tk.Button(self, text = "Addition of Vectors - Scale Drawing", command=lambda: controller.show_frame(AdditionVectorsScaleDrawingPage))
855 self.ResolutionOfVectorsButton = tk.Button(self, text = "Resolution of Vectors", command=lambda: controller.show_frame(ResolutionOfVectorsPage))
856 self.VectorsInEquilibriumButton = tk.Button(self, text = "Vectors in Equilibrium", command=lambda: controller.show_frame(VectorsInEquilibriumPage))
857 self.InclinedPlaneVectorsButton = tk.Button(self, text = "Inclined Plane Vectors", command=lambda: controller.show_frame(InclinedPlaneVectorsPage))
858
859 self.label.pack(side="top", fill="x", pady=10)
860 self.ScalarsVectorsButton.pack(side="top", pady=15, ipadx=10)
861 self.AdditionVectorsCalculationButton.pack(side="top", pady=15, ipadx=10)
862 self.AdditionVectorsScaleDrawingButton.pack(side="top", pady=15, ipadx=10)
863 self.ResolutionOfVectorsButton.pack(side="top", pady=15, ipadx=10)
864 self.VectorsInEquilibriumButton.pack(side="top", pady=15, ipadx=10)
865 self.InclinedPlaneVectorsButton.pack(side="top", pady=15, ipadx=10)
866
867class ScalarsVectorsPage(tk.Frame):
868
869 def __init__(self, parent, controller):
870
871 tk.Frame.__init__(self, parent)
872 self.title = tk.Label(self, text="Scalars and Vectors Page", font=LARGEFONT)
873 self.title.pack(padx=10, pady=10)
874
875 self.canvas = Canvas(self, width=800, height=500, bd=2)
876 self.canvas.pack()
877
878 self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnForces())
879 self.returnButton.pack(ipadx=10)
880
881 self.canvas.create_line(400, 0, 400, 350)
882 self.canvas.create_line(400, 400, 400, 500)
883 self.canvas.create_line(20, 375, 325, 375)
884 self.canvas.create_line(475, 375, 780, 375)
885
886 self.canvas.create_text(200, 15, text = "Scalars", font = MEDIUMFONT)
887 self.canvas.create_line(100, 175, 300, 75, arrow=BOTH, arrowshape="2 1 10")
888 self.canvas.create_text(160, 100, text = "2 metres", font = LABELFONT)
889 self.canvas.create_text(200, 250, text = "Scalars have size / length / magnitude", font = LABELFONT)
890 self.canvas.create_text(200, 300, text = "They have no direction", font = MEDIUMFONT)
891
892 self.canvas.create_text(600, 15, text = "Vectors", font = MEDIUMFONT)
893 self.canvas.create_text(500, 60, text = "North", font = LABELFONT)
894 self.canvas.create_line(500, 175, 500, 75, arrow=LAST) # North arrow
895 self.canvas.create_line(500, 175, 700, 75, arrow=LAST) # Scalar arrow
896 self.canvas.create_arc(475, 150, 525, 200, start = 90.0, extent = -63.44)
897 self.canvas.create_text(660, 135, text = "2 metres", font = LABELFONT)
898 self.canvas.create_text(520, 140, text = "Θ", font = LABELFONT)
899 self.canvas.create_text(600, 250, text = "Vectors have size / length / magnitude", font = LABELFONT)
900 self.canvas.create_text(600, 300, text = "They also have a direction / bearing", font = LABELFONT)
901
902 self.canvas.create_text(400, 375, text = "Examples", font = MEDIUMFONT)
903
904 self.canvas.create_text(120, 435, text = "Speed", font = MEDIUMFONT)
905 self.canvas.create_text(200, 470, text = "Mass", font = MEDIUMFONT)
906 self.canvas.create_text(280, 435, text = "Distance", font = MEDIUMFONT)
907
908 self.canvas.create_text(465, 435, text = "Velocity", font = MEDIUMFONT)
909 self.canvas.create_text(515, 470, text = "Force", font = MEDIUMFONT)
910 self.canvas.create_text(565, 435, text = "Weight", font = MEDIUMFONT)
911 self.canvas.create_text(650, 470, text = "Acceleration", font = MEDIUMFONT)
912 self.canvas.create_text(700, 435, text = "Displacement", font = MEDIUMFONT)
913
914 def returnForces():
915 window.addScore(2)
916 messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
917 controller.show_frame(forcesPage)
918
919class AdditionVectorsCalculationPage(tk.Frame):
920
921 def __init__(self, parent, controller):
922
923 tk.Frame.__init__(self, parent)
924 self.title = tk.Label(self, text="Addition of Vectors - Calculation Page", font=LARGEFONT)
925 self.title.pack(padx=10, pady=10)
926
927 self.canvas = Canvas(self, width=800, height=500, bd=2)
928 self.canvas.pack()
929
930 self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnForces())
931 self.returnButton.pack(ipadx=10)
932
933 self.canvas.create_line(25, 150, 425, 20, arrow=LAST, arrowshape="16 20 6")
934 self.canvas.create_rectangle(400, 125, 425, 150)
935 self.canvas.create_arc(-50, 100, 100, 200, extent = 25.5)
936 self.canvas.create_text(110, 135, text = "Θ", font = LABELFONT)
937
938 self.canvas.create_line(425, 150, 425,50, arrow=LAST, arrowshape="12 16 4", fill="red")
939 self.canvas.create_line(425, 50, 425, 20, fill="red")
940 self.canvas.create_line(25, 150, 375, 150, arrow=LAST, arrowshape="12 16 4", fill="blue")
941 self.canvas.create_line(375, 150, 425, 150, fill="blue")
942 self.canvas.create_text(450, 75, text = "a", font = LABELFONT, fill="red")
943 self.canvas.create_text(225, 170, text = "b", font = LABELFONT, fill="blue")
944 self.canvas.create_text(225, 50, text = "c", font = LABELFONT)
945
946 self.canvas.create_text(625, 75, text = """You will only ever be asked
947to add vectors by calculation
948with vectors at right angles
949
950Therefore, addition of vectors
951by calculation simply requires
952Pythagoras's Theorem""", font = LABELFONT)
953
954 self.canvas.create_text(175, 225, text = "PYTHAGORAS", font = LARGEFONT)
955 self.canvas.create_text(175, 275, text = "a^2 + b^2 = c^2", font = LARGEFONT)
956 self.canvas.create_text(175, 375, text = "TRIGONOMETRY", font = LARGEFONT)
957 self.canvas.create_text(175, 425, text = "tan Θ = a / b", font = LARGEFONT)
958 self.canvas.create_text(550, 325, text = """You may be asked to find the final vector
959after travelling along two vectors
960
961In which case, substitute in 'a' and 'b'
962and rearrange to find 'c'
963which will be your vector's magnitude
964Use trigonometry to find
965the angle of the vector""", font = LABELFONT)
966
967 def returnForces():
968 window.addScore(2)
969 messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
970 controller.show_frame(forcesPage)
971
972class AdditionVectorsScaleDrawingPage(tk.Frame):
973
974 def __init__(self, parent, controller):
975
976 tk.Frame.__init__(self, parent)
977 self.title = tk.Label(self, text="Addition of Vectors - Scale Drawing Page", font=LARGEFONT)
978 self.title.pack(padx=10, pady=10)
979
980 self.canvas = Canvas(self, width=800, height=500, bd=2)
981 self.canvas.pack()
982
983 self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnForces())
984 self.returnButton.pack(ipadx=10)
985
986 self.canvas.create_text(50, 10, text = "North", font = LABELFONT)
987 self.canvas.create_line(50, 200, 50, 20, dash=True, arrow=LAST, arrowshape="12 16 4") # North Arrow
988 self.canvas.create_arc(25, 175, 75, 225, start = 90.0, extent = -45.0)
989
990 self.canvas.create_text(175, 10, text = "North", font = LABELFONT)
991 self.canvas.create_line(175, 75, 175, 20, dash=True, arrow=LAST, arrowshape="12 16 4") # North Arrow
992 self.canvas.create_rectangle(175, 75, 190, 60)
993
994 self.canvas.create_line(50, 200, 175, 75, arrow=LAST, arrowshape="16 20 6", fill="red")
995 self.canvas.create_line(175, 75, 425, 75, arrow=LAST, arrowshape="16 20 6", fill="blue")
996 self.canvas.create_text(160, 155, text = "10 KM\nVector a", font = LABELFONT, fill="red")
997 self.canvas.create_text(300, 100, text = "20 KM\nVector b", font = LABELFONT, fill="blue")
998 self.canvas.create_text(75, 145, text = "45°", font = LABELFONT)
999 self.canvas.create_text(620, 125, text = """You can be asked to add two vectors
1000by scale drawing
1001
1002The angle between these vectors is
1003NOT limited to right angles
1004
1005You must draw the vectors
1006to scale""", font = LABELFONT)
1007
1008 self.canvas.create_text(400, 240, text = "DRAW TO SCALE - DECLARE YOUR SCALE", font = LARGEFONT)
1009 self.canvas.create_rectangle(15, 285, 145, 315)
1010 self.canvas.create_text(80, 300, text = "1 KM = 1 CM", font = LABELFONT)
1011
1012 self.canvas.create_text(50, 340, text = "North", font = LABELFONT)
1013 self.canvas.create_line(50, 460, 50, 350, dash=True, arrow=LAST, arrowshape="12 16 4") # North Arrow
1014 self.canvas.create_arc(25, 435, 75, 485, start = 90.0, extent = -72.5)
1015 self.canvas.create_text(65, 425, text = "Θ", font = LABELFONT)
1016
1017 self.canvas.create_line(50, 460, 175, 335, arrow=LAST, arrowshape="16 20 6", fill="red")
1018 self.canvas.create_line(175, 335, 425, 335, arrow=LAST, arrowshape="16 20 6", fill="blue")
1019 self.canvas.create_text(120, 370, text = "a", font = LABELFONT, fill="red")
1020 self.canvas.create_text(280, 320, text = "b", font = LABELFONT, fill="blue")
1021 self.canvas.create_text(150, 400, text = "10 CM", font = LABELFONT, fill="red")
1022 self.canvas.create_text(280, 355, text = "20 CM", font = LABELFONT, fill="blue")
1023 self.canvas.create_line(50, 460, 425, 335, fill="red")
1024 self.canvas.create_line(50, 460, 425, 335, dash=True, fill="blue")
1025 self.canvas.create_text(300, 420, text = "Resultant Vector", font = MEDIUMFONT, fill="red")
1026
1027 self.canvas.create_text(620, 375, text = "For the magnitude, measure\nthe resultant vector using\na ruler\n\nFor the angle, measure\nΘ with a protractor", font = LABELFONT)
1028
1029 def returnForces():
1030 window.addScore(2)
1031 messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
1032 controller.show_frame(forcesPage)
1033
1034class ResolutionOfVectorsPage(tk.Frame):
1035
1036 def __init__(self, parent, controller):
1037
1038 tk.Frame.__init__(self, parent)
1039 self.title = tk.Label(self, text="Resolution of Vectors Page", font=LARGEFONT)
1040 self.title.pack(padx=10, pady=10)
1041
1042 self.canvas = Canvas(self, width=800, height=500, bd=2)
1043 self.canvas.pack()
1044
1045 self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnForces())
1046 self.returnButton.pack(ipadx=10)
1047
1048 self.canvas.create_line(50, 150, 450, 20, arrow=LAST, arrowshape="16 20 6")
1049 self.canvas.create_line(50, 150, 50, 20, dash=True, arrow=LAST, arrowshape="12 16 4", fill="red")
1050 self.canvas.create_line(50, 150, 450, 150, dash=True, arrow=LAST, arrowshape="12 16 4", fill="blue")
1051 self.canvas.create_text(250, 50, text = "? ms^-1", font = LABELFONT)
1052 self.canvas.create_text(100, 75, text = "3 ms^-1", font = LABELFONT, fill="red")
1053 self.canvas.create_text(250, 175, text = "4 ms^-1", font = LABELFONT, fill="blue")
1054 self.canvas.create_text(625, 100, text = """Similar to addition of vectors
1055by calculation
1056
1057Every vector has a vertical
1058and horizontal component
1059
1060Simply add the two components
1061in order to find the vector's
1062magnitude""", font = LABELFONT)
1063
1064 self.canvas.create_line(350, 390, 750, 240, arrow=LAST, arrowshape="16 20 6")
1065 self.canvas.create_rectangle(725, 365, 750, 390)
1066 self.canvas.create_arc(300, 340, 400, 440, extent = 20.5)
1067 self.canvas.create_text(420, 377, text = "Θ", font = LABELFONT)
1068
1069 self.canvas.create_line(750, 390, 750, 290, arrow=LAST, arrowshape="12 16 4", fill="red")
1070 self.canvas.create_line(750, 290, 750, 240, fill="red")
1071 self.canvas.create_line(350, 390, 700, 390, arrow=LAST, arrowshape="12 16 4", fill="blue")
1072 self.canvas.create_line(700, 390, 750, 390, fill="blue")
1073 self.canvas.create_text(775, 315, text = "a", font = LABELFONT, fill="red")
1074 self.canvas.create_text(550, 410, text = "b", font = LABELFONT, fill="blue")
1075 self.canvas.create_text(550, 290, text = "c", font = LABELFONT)
1076
1077 self.canvas.create_text(100, 245, text = "a^2 + b^2 = c^2", font = LABELFONT)
1078 self.canvas.create_text(100, 295, text = "3^2 + 4^2 = c^2", font = LABELFONT)
1079 self.canvas.create_text(100, 345, text = "c^2 = 25", font = LABELFONT)
1080 self.canvas.create_text(100, 395, text = "c = 5", font = LABELFONT)
1081 self.canvas.create_text(310, 245, text = "arg Θ = 3 / 4", font = LABELFONT)
1082 self.canvas.create_text(310, 295, text = "Θ = tan^-1( 0.75 )", font = LABELFONT)
1083 self.canvas.create_text(310, 345, text = "Θ ≈ 53°", font = LABELFONT)
1084
1085 self.canvas.create_text(475, 465, text = "Vector Magnitude is 5 ms^-1, Vector Angle is 53°", font = LABELFONT)
1086
1087 def returnForces():
1088 window.addScore(2)
1089 messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
1090 controller.show_frame(forcesPage)
1091
1092class VectorsInEquilibriumPage(tk.Frame):
1093
1094 def __init__(self, parent, controller):
1095
1096 tk.Frame.__init__(self, parent)
1097 self.title = tk.Label(self, text="Vectors In Equilibrium Page", font=LARGEFONT)
1098 self.title.pack(padx=10, pady=10)
1099
1100 self.canvas = Canvas(self, width=800, height=500, bd=2)
1101 self.canvas.pack()
1102
1103 self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnForces())
1104 self.returnButton.pack(ipadx=10)
1105
1106 self.canvas.create_text(400, 20, text = "F = ma", font = LARGEFONT)
1107 self.canvas.create_text(400, 50, text = "When an object is in equilibrium, the resultant force acting on it is 0", font = LABELFONT)
1108 self.canvas.create_text(400, 70, text = "If F = 0, ma = 0. Assuming the object has mass, when in equilibrium, acceleration = 0", font = LABELFONT)
1109 self.canvas.create_text(400, 90, text = "When acceleration = 0, the object has constant velocity", font = LABELFONT)
1110 # Underline
1111 self.canvas.create_line(160, 102, 640, 102)
1112
1113 # Page divider
1114 self.canvas.create_line(400, 110, 400, 490)
1115
1116 # At rest
1117 self.canvas.create_text(200, 135, text = "Objects in equilibrium - at rest", font = MEDIUMFONT)
1118 self.canvas.create_line(20, 260, 380, 260)
1119 self.canvas.create_rectangle(175, 210, 225, 260)
1120 self.canvas.create_oval(198, 233, 202, 237, fill="black")
1121 self.canvas.create_text(50, 250, text = "Table", font = SMALLFONT)
1122
1123 self.canvas.create_line(200, 160, 200, 235, fill="blue", arrow=FIRST)
1124 self.canvas.create_text(280, 185, text = "Reaction Force", font = LABELFONT, fill="blue")
1125 self.canvas.create_line(200, 235, 200, 310, fill="red", arrow=LAST)
1126 self.canvas.create_text(165, 285, text = "Weight ", font = LABELFONT, fill="red")
1127
1128 self.canvas.create_text(200, 350, text = "The table supports the block by exerting a", font = LABELFONT)
1129 self.canvas.create_text(200, 390, text = "reaction force equal to the blocks weight", font = LABELFONT)
1130 self.canvas.create_text(200, 430, text = "Resultant force is 0 and so its acceleration", font = LABELFONT)
1131 self.canvas.create_text(200, 470, text = "is 0. Therefore it stays at rest", font = LABELFONT)
1132
1133 # Moving
1134 self.canvas.create_text(600, 135, text = "Objects in equilibrium - moving", font = MEDIUMFONT)
1135 self.canvas.create_text(600, 180, text = "Velocity = 30 ms^-1", font = LABELFONT)
1136 self.canvas.create_line(420, 290, 780, 290)
1137 try:
1138 self.Car = tk.PhotoImage(file = "NEACar1.png")
1139 self.canvas.create_image(600, 260, image=self.Car)
1140 except:
1141 self.canvas.create_text(600, 260, text = "Car Image not found")
1142 self.canvas.create_line(537, 260, 450, 260, fill="red", arrow=LAST)
1143 self.canvas.create_text(490, 240, text = "Thrust ", font = LABELFONT, fill="red")
1144 self.canvas.create_line(663, 260, 750, 260, fill="blue", arrow=LAST)
1145 self.canvas.create_text(710, 230, text = "Air Resistance", font = LABELFONT, fill="blue")
1146 self.canvas.create_line(635, 290, 750, 290, fill="blue", arrow=LAST)
1147 self.canvas.create_text(690, 305, text = "Friction", font = LABELFONT, fill="blue")
1148
1149 self.canvas.create_text(600, 345, text = "If in equilibrium,", font = LABELFONT)
1150 self.canvas.create_text(600, 375, text = "Thrust = Air Resistance + Friction,", font = LABELFONT)
1151 self.canvas.create_text(600, 405, text = "so the overall force on the car is 0", font = LABELFONT)
1152 self.canvas.create_text(600, 435, text = "So its acceleration is 0", font = LABELFONT)
1153 self.canvas.create_text(600, 465, text = "Therefore it stays at its current velocity", font = LABELFONT)
1154
1155
1156 def returnForces():
1157 window.addScore(2)
1158 messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
1159 controller.show_frame(forcesPage)
1160
1161class InclinedPlaneVectorsPage(tk.Frame):
1162
1163 def __init__(self, parent, controller):
1164
1165 tk.Frame.__init__(self, parent)
1166 self.title = tk.Label(self, text="Inclined Plane Vectors Page", font=LARGEFONT)
1167 self.title.pack(padx=10, pady=10)
1168
1169 self.canvas = Canvas(self, width=800, height=500, bd=2)
1170 self.canvas.pack()
1171
1172 self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnForces())
1173 self.returnButton.pack(ipadx=10)
1174
1175 self.canvas.create_text(400, 25, text = "When an object is stationary on an inclined plane, 3 forces are acting on it", font = MEDIUMFONT)
1176 self.canvas.create_text(400, 50, text = "1. Weight of the object, acting vertically downwards", font = SMALLFONT)
1177 self.canvas.create_text(400, 75, text = "2. The Support / Reaction force, acting perpendicular to where the weight acts on the plane", font = SMALLFONT)
1178 self.canvas.create_text(400, 100, text = "3. Friction, acting parallel to the plane", font = SMALLFONT)
1179
1180 # Box
1181 self.canvas.create_polygon(120, 225, 160, 215, 150, 175, 110, 185, fill="white", outline="black")
1182 self.canvas.create_oval(133, 198, 137, 202, fill="black")
1183
1184 # Weight arrow
1185 self.canvas.create_line(135, 125, 135, 220, fill="green", arrow=LAST)
1186 self.canvas.create_text(160, 150, text = "Weight", fill="green")
1187
1188 # Support Arrow
1189 self.canvas.create_line(135, 220, 90, 135, fill="blue", arrow=LAST)
1190 self.canvas.create_text(70, 160, text = "Support", fill="blue")
1191
1192 # Friction Arrows
1193 self.canvas.create_line(90, 135, 135, 125, fill="red", arrow=LAST)
1194 self.canvas.create_text(105, 115, text = "Friction", fill="red")
1195 self.canvas.create_line(135, 220, 175, 210, fill="red", arrow=LAST)
1196
1197 # Triangle
1198 self.canvas.create_arc(-40, 190, 80, 310, extent = 14.0)
1199 self.canvas.create_line(20, 250, 500, 250, fill="green")
1200 self.canvas.create_line(500, 250, 420, 150, fill="red")
1201 self.canvas.create_line(20, 250, 420, 150, fill="blue")
1202 self.canvas.create_text(100, 240, text = "Θ", font = SMALLFONT)
1203
1204 self.canvas.create_text(650, 200, text = "As colour coordinated, one can see\nthat the rules of similar triangles\ncan be used\n\nThis allows us to form this triangle ↓", font = SMALLFONT)
1205
1206 # New Triangle
1207 self.canvas.create_arc(210, 390, 330, 510, extent = 14.0)
1208 self.canvas.create_line(270, 450, 750, 450, fill="green", arrow=FIRST)
1209 self.canvas.create_line(750, 450, 670, 350, fill="red", arrow=FIRST)
1210 self.canvas.create_line(270, 450, 670, 350, fill="blue", arrow=LAST)
1211 self.canvas.create_text(350, 440, text = "Θ", font = SMALLFONT)
1212 self.canvas.create_text(550, 465, text = "Weight", fill="green")
1213 self.canvas.create_text(470, 380, text = "Support", fill="blue")
1214 self.canvas.create_text(740, 390, text = "Friction", fill="red")
1215
1216 self.canvas.create_text(320, 350, text = """If asked to find out the angle of the inclined plane, use trigonometry
1217and your values of weight, support and friction to find Θ
1218
1219As the triangle's overall displacement is zero,
1220an unknown weight, support or friction force
1221will be equal to the negative sum of the
1222known values
1223e.g. W = -(S + F)""", font = LABELFONT)
1224 self.canvas.create_text(125, 475, text = "W + S + F = 0", font = MEDIUMFONT)
1225
1226 def returnForces():
1227 window.addScore(2)
1228 messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
1229 controller.show_frame(forcesPage)
1230
1231# Time Graoh Pages #
1232
1233class timeGraphsPage(tk.Frame):
1234
1235 def __init__(self, parent, controller):
1236
1237 tk.Frame.__init__(self, parent)
1238 self.title = tk.Label(self, text="Time Graphs Page", font=LARGEFONT)
1239 self.title.pack(padx=10, pady=10)
1240
1241 self.label = tk.Label(self, text = "Time Graphs:", font = MEDIUMFONT)
1242 self.GradientsButton = tk.Button(self, text = "Gradients", command=lambda: controller.show_frame(GradientsPage))
1243 self.AreaUnderCurveButton = tk.Button(self, text = "Area Under Curve", command=lambda: controller.show_frame(AreaUnderCurvePage))
1244 self.BouncingBallbutton = tk.Button(self, text = "Experiment - Bouncing Ball", command=lambda: controller.show_frame(BouncingBallPage))
1245
1246 self.label.pack(side="top", fill="x", pady=10)
1247 self.GradientsButton.pack(side="top", pady=15, ipadx=10)
1248 self.AreaUnderCurveButton.pack(side="top", pady=15, ipadx=10)
1249 self.BouncingBallbutton.pack(side="top", pady=15, ipadx=10)
1250
1251class GradientsPage(tk.Frame):
1252
1253 def __init__(self, parent, controller):
1254
1255 tk.Frame.__init__(self, parent)
1256 self.title = tk.Label(self, text="Gradients Of Time Graphs Page", font=LARGEFONT)
1257 self.title.grid(row=0 , column=0, columnspan=2, padx=10, pady=10)
1258
1259 self.distanceCanvas = Canvas(self, width=400, height=160, bd=2)
1260 self.distanceCanvas.grid(row=1, column=0)
1261 self.displacementCanvas = Canvas(self, width=400, height=160, bd=2)
1262 self.displacementCanvas.grid(row=1, column=1)
1263 self.speedCanvas = Canvas(self, width=400, height=160, bd=2)
1264 self.speedCanvas.grid(row=2, column=0)
1265 self.velocityCanvas = Canvas(self, width=400, height=160, bd=2)
1266 self.velocityCanvas.grid(row=2, column=1)
1267 self.accelerationCanvas = Canvas(self, width=400, height=160, bd=2)
1268 self.accelerationCanvas.grid(row=3, column=0, columnspan=2)
1269
1270 self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnForces())
1271 self.returnButton.grid(row=4, column=0, ipadx=10)
1272
1273 self.scalarVectorLabel = tk.Label(self, text = "Blue = Scalar , Red = Vector")
1274 self.scalarVectorLabel.grid(row=4, column=1, padx=5)
1275
1276 self.distanceCanvas.create_text(200, 15, text = "Distance - Time Graph",font = MEDIUMFONT, fill="blue")
1277 self.distanceCanvas.create_line(50, 135, 50, 35, width = 3, fill="blue")
1278 self.distanceCanvas.create_line(50, 135, 200, 135, width = 3, fill="blue")
1279 self.distanceCanvas.create_line(50, 135, 195, 40, fill="blue")
1280 self.distanceCanvas.create_text(25, 85, text = "d",font = LABELFONT, fill="blue")
1281 self.distanceCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="blue")
1282 self.distanceCanvas.create_text(300, 55, text = "Gradient",font = LABELFONT, fill="blue")
1283 self.distanceCanvas.create_text(300, 85, text = "= d / t",font = LABELFONT, fill="blue")
1284 self.distanceCanvas.create_text(300, 115, text = "= Speed",font = LABELFONT, fill="blue")
1285
1286 self.displacementCanvas.create_text(200, 15, text = "Displacement - Time Graph",font = MEDIUMFONT, fill="red")
1287 self.displacementCanvas.create_line(50, 135, 50, 35, width = 3, fill="red")
1288 self.displacementCanvas.create_line(50, 135, 200, 135, width = 3, fill="red")
1289 self.displacementCanvas.create_line(50, 135, 195, 40, fill="red")
1290 self.displacementCanvas.create_text(25, 85, text = "s",font = LABELFONT, fill="red")
1291 self.displacementCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="red")
1292 self.displacementCanvas.create_text(300, 55, text = "Gradient",font = LABELFONT, fill="red")
1293 self.displacementCanvas.create_text(300, 85, text = "= s / t",font = LABELFONT, fill="red")
1294 self.displacementCanvas.create_text(300, 115, text = "= Velocity",font = LABELFONT, fill="red")
1295
1296 self.speedCanvas.create_text(200, 15, text = "Speed - Time Graph",font = MEDIUMFONT, fill="blue")
1297 self.speedCanvas.create_line(50, 135, 50, 35, width = 3, fill="blue")
1298 self.speedCanvas.create_line(50, 135, 200, 135, width = 3, fill="blue")
1299 self.speedCanvas.create_line(50, 135, 195, 40, fill="blue")
1300 self.speedCanvas.create_text(25, 85, text = "s",font = LABELFONT, fill="blue")
1301 self.speedCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="blue")
1302 self.speedCanvas.create_text(300, 55, text = "Gradient",font = LABELFONT, fill="blue")
1303 self.speedCanvas.create_text(300, 85, text = "= s / t",font = LABELFONT, fill="blue")
1304 self.speedCanvas.create_text(300, 115, text = "Not needed for exam",font = LABELFONT, fill="blue")
1305
1306 self.velocityCanvas.create_text(200, 15, text = "Velocity - Time Graph",font = MEDIUMFONT, fill="red")
1307 self.velocityCanvas.create_line(50, 135, 50, 35, width = 3, fill="red")
1308 self.velocityCanvas.create_line(50, 135, 200, 135, width = 3, fill="red")
1309 self.velocityCanvas.create_line(50, 135, 195, 40, fill="red")
1310 self.velocityCanvas.create_text(25, 85, text = "v",font = LABELFONT, fill="red")
1311 self.velocityCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="red")
1312 self.velocityCanvas.create_text(300, 55, text = "Gradient",font = LABELFONT, fill="red")
1313 self.velocityCanvas.create_text(300, 85, text = "= v / t",font = LABELFONT, fill="red")
1314 self.velocityCanvas.create_text(300, 115, text = "Acceleration",font = LABELFONT, fill="red")
1315
1316 self.accelerationCanvas.create_text(200, 15, text = "Acceleration - Time Graph",font = MEDIUMFONT, fill="red")
1317 self.accelerationCanvas.create_line(50, 135, 50, 35, width = 3, fill="red")
1318 self.accelerationCanvas.create_line(50, 135, 200, 135, width = 3, fill="red")
1319 self.accelerationCanvas.create_line(50, 135, 195, 40, fill="red")
1320 self.accelerationCanvas.create_text(25, 85, text = "a",font = LABELFONT, fill="red")
1321 self.accelerationCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="red")
1322 self.accelerationCanvas.create_text(300, 55, text = "Gradient",font = LABELFONT, fill="red")
1323 self.accelerationCanvas.create_text(300, 85, text = "= a / t",font = LABELFONT, fill="red")
1324 self.accelerationCanvas.create_text(300, 115, text = "Not needed for exam",font = LABELFONT, fill="red")
1325
1326 def returnForces():
1327 window.addScore(2)
1328 messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
1329 controller.show_frame(timeGraphsPage)
1330
1331class AreaUnderCurvePage(tk.Frame):
1332
1333 def __init__(self, parent, controller):
1334
1335 tk.Frame.__init__(self, parent)
1336 self.title = tk.Label(self, text="Area Under Curves Of Time Graphs Page", font=LARGEFONT)
1337 self.title.grid(row=0, column=0, columnspan=2, padx=10, pady=10)
1338
1339 self.distanceCanvas = Canvas(self, width=400, height=160, bd=2)
1340 self.distanceCanvas.grid(row=1, column=0)
1341 self.displacementCanvas = Canvas(self, width=400, height=160, bd=2)
1342 self.displacementCanvas.grid(row=1, column=1)
1343 self.speedCanvas = Canvas(self, width=400, height=160, bd=2)
1344 self.speedCanvas.grid(row=2, column=0)
1345 self.velocityCanvas = Canvas(self, width=400, height=160, bd=2)
1346 self.velocityCanvas.grid(row=2, column=1)
1347 self.accelerationCanvas = Canvas(self, width=400, height=160, bd=2)
1348 self.accelerationCanvas.grid(row=3, column=0, columnspan=2)
1349
1350 self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnForces())
1351 self.returnButton.grid(row=4, column=0, ipadx=10)
1352
1353 self.scalarVectorLabel = tk.Label(self, text = "Blue = Scalar , Red = Vector")
1354 self.scalarVectorLabel.grid(row=4, column=1, padx=5)
1355
1356 self.distanceCanvas.create_text(200, 15, text = "Distance - Time Graph",font = MEDIUMFONT, fill="blue")
1357 self.distanceCanvas.create_line(50, 135, 50, 35, width = 3, fill="blue")
1358 self.distanceCanvas.create_line(50, 135, 200, 135, width = 3, fill="blue")
1359 self.distanceCanvas.create_line(50, 135, 195, 40, fill="blue")
1360 self.distanceCanvas.create_text(25, 85, text = "d",font = LABELFONT, fill="blue")
1361 self.distanceCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="blue")
1362 self.distanceCanvas.create_text(300, 55, text = "Area Under Curve",font = LABELFONT, fill="blue")
1363 self.distanceCanvas.create_text(300, 85, text = "= d x t",font = LABELFONT, fill="blue")
1364 self.distanceCanvas.create_text(300, 115, text = "Not needed for exam",font = LABELFONT, fill="blue")
1365
1366 self.displacementCanvas.create_text(200, 15, text = "Displacement - Time Graph",font = MEDIUMFONT, fill="red")
1367 self.displacementCanvas.create_line(50, 135, 50, 35, width = 3, fill="red")
1368 self.displacementCanvas.create_line(50, 135, 200, 135, width = 3, fill="red")
1369 self.displacementCanvas.create_line(50, 135, 195, 40, fill="red")
1370 self.displacementCanvas.create_text(25, 85, text = "s",font = LABELFONT, fill="red")
1371 self.displacementCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="red")
1372 self.displacementCanvas.create_text(300, 55, text = "Area Under Curve",font = LABELFONT, fill="red")
1373 self.displacementCanvas.create_text(300, 85, text = "= s x t",font = LABELFONT, fill="red")
1374 self.displacementCanvas.create_text(300, 115, text = "Not needed for exam",font = LABELFONT, fill="red")
1375
1376 self.speedCanvas.create_text(200, 15, text = "Speed - Time Graph",font = MEDIUMFONT, fill="blue")
1377 self.speedCanvas.create_line(50, 135, 50, 35, width = 3, fill="blue")
1378 self.speedCanvas.create_line(50, 135, 200, 135, width = 3, fill="blue")
1379 self.speedCanvas.create_line(50, 135, 195, 40, fill="blue")
1380 self.speedCanvas.create_text(25, 85, text = "s",font = LABELFONT, fill="blue")
1381 self.speedCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="blue")
1382 self.speedCanvas.create_text(300, 55, text = "Area Under Curve",font = LABELFONT, fill="blue")
1383 self.speedCanvas.create_text(300, 85, text = "= s x t",font = LABELFONT, fill="blue")
1384 self.speedCanvas.create_text(300, 115, text = "= Distance",font = LABELFONT, fill="blue")
1385
1386 self.velocityCanvas.create_text(200, 15, text = "Velocity - Time Graph",font = MEDIUMFONT, fill="red")
1387 self.velocityCanvas.create_line(50, 135, 50, 35, width = 3, fill="red")
1388 self.velocityCanvas.create_line(50, 135, 200, 135, width = 3, fill="red")
1389 self.velocityCanvas.create_line(50, 135, 195, 40, fill="red")
1390 self.velocityCanvas.create_text(25, 85, text = "v",font = LABELFONT, fill="red")
1391 self.velocityCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="red")
1392 self.velocityCanvas.create_text(300, 55, text = "Area Under Curve",font = LABELFONT, fill="red")
1393 self.velocityCanvas.create_text(300, 85, text = "= v x t",font = LABELFONT, fill="red")
1394 self.velocityCanvas.create_text(300, 115, text = "Displacement",font = LABELFONT, fill="red")
1395
1396 self.accelerationCanvas.create_text(200, 15, text = "Acceleration - Time Graph",font = MEDIUMFONT, fill="red")
1397 self.accelerationCanvas.create_line(50, 135, 50, 35, width = 3, fill="red")
1398 self.accelerationCanvas.create_line(50, 135, 200, 135, width = 3, fill="red")
1399 self.accelerationCanvas.create_line(50, 135, 195, 40, fill="red")
1400 self.accelerationCanvas.create_text(25, 85, text = "a",font = LABELFONT, fill="red")
1401 self.accelerationCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="red")
1402 self.accelerationCanvas.create_text(300, 55, text = "Area Under Curve",font = LABELFONT, fill="red")
1403 self.accelerationCanvas.create_text(300, 85, text = "= a x t",font = LABELFONT, fill="red")
1404 self.accelerationCanvas.create_text(300, 115, text = "Velocity",font = LABELFONT, fill="red")
1405
1406 def returnForces():
1407 window.addScore(2)
1408 messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
1409 controller.show_frame(timeGraphsPage)
1410
1411class BouncingBallPage(tk.Frame):
1412
1413 def __init__(self, parent, controller):
1414
1415 tk.Frame.__init__(self, parent)
1416 self.title = tk.Label(self, text="Bouncing Ball Example Page", font=LARGEFONT)
1417 self.title.grid(row=0, column=0, columnspan=2, padx=10, pady=10)
1418
1419 self.bouncingBallCanvas = Canvas(self, width=400, height=160, bd=2)
1420 self.bouncingBallCanvas.grid(row=1, column=0)
1421 self.distanceCanvas = Canvas(self, width=400, height=160, bd=2)
1422 self.distanceCanvas.grid(row=1, column=1)
1423 self.displacementCanvas = Canvas(self, width=400, height=160, bd=2)
1424 self.displacementCanvas.grid(row=2, column=0)
1425 self.speedCanvas = Canvas(self, width=400, height=160, bd=2)
1426 self.speedCanvas.grid(row=2, column=1)
1427 self.velocityCanvas = Canvas(self, width=400, height=160, bd=2)
1428 self.velocityCanvas.grid(row=3, column=0)
1429 self.accelerationCanvas = Canvas(self, width=400, height=160, bd=2)
1430 self.accelerationCanvas.grid(row=3, column=1)
1431
1432 self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnForces())
1433 self.returnButton.grid(row=4, column=0, ipadx=10)
1434
1435 self.scalarVectorLabel = tk.Label(self, text = "Blue = Scalar , Red = Vector")
1436 self.scalarVectorLabel.grid(row=4, column=1, padx=5)
1437
1438 self.bouncingBallCanvas.create_oval(50, 10, 90, 50, fill="gray40", outline="gray40")
1439 self.bouncingBallCanvas.create_oval(50, 150, 90, 110, fill="gray40", outline="gray40")
1440 self.bouncingBallCanvas.create_line(60, 50, 60, 110, width=2)
1441 self.bouncingBallCanvas.create_line(80, 50, 80, 110, width=2)
1442 self.bouncingBallCanvas.create_line(60, 50, 45, 65, width=2)
1443 self.bouncingBallCanvas.create_line(80, 110, 95, 95, width=2)
1444 self.bouncingBallCanvas.create_line(20, 152, 130, 152, width = 3)
1445 self.bouncingBallCanvas.create_text(265, 30, text = "Common Exam Question", font = MEDIUMFONT)
1446 self.bouncingBallCanvas.create_text(265, 70, text = "Ball projected upward, whilst", font = SMALLFONT)
1447 self.bouncingBallCanvas.create_text(265, 100, text = "in the air, it is acted on", font = SMALLFONT)
1448 self.bouncingBallCanvas.create_text(265, 130, text = "by gravity only", font = SMALLFONT)
1449
1450 self.distanceCanvas.create_text(200, 15, text = "Distance - Time Graph", font = MEDIUMFONT, fill="blue")
1451 self.distanceCanvas.create_line(125, 135, 125, 35, width = 3, fill="blue")
1452 self.distanceCanvas.create_line(125, 135, 275, 135, width = 3, fill="blue")
1453 self.distanceCanvas.create_arc(127, 85, 275, 185, start=90, extent=90, style="arc", outline="blue")
1454 self.distanceCanvas.create_arc(127, -15, 275, 85, start=-90, extent=90, style="arc", outline="blue")
1455 self.distanceCanvas.create_text(100, 85, text = "d",font = LABELFONT, fill="blue")
1456 self.distanceCanvas.create_text(200, 153, text = "t",font = LABELFONT, fill="blue")
1457
1458 self.displacementCanvas.create_text(200, 15, text = "Displacement - Time Graph",font = MEDIUMFONT, fill="red")
1459 self.displacementCanvas.create_line(125, 135, 125, 35, width = 3, fill="red")
1460 self.displacementCanvas.create_line(125, 135, 275, 135, width = 3, fill="red")
1461 self.displacementCanvas.create_arc(127, 35, 275, 235, extent=180, style="arc", outline="red")
1462 self.displacementCanvas.create_text(100, 85, text = "s",font = LABELFONT, fill="red")
1463 self.displacementCanvas.create_text(200, 153, text = "t",font = LABELFONT, fill="red")
1464
1465 self.speedCanvas.create_text(200, 15, text = "Speed - Time Graph",font = MEDIUMFONT, fill="blue")
1466 self.speedCanvas.create_line(125, 135, 125, 35, width = 3, fill="blue")
1467 self.speedCanvas.create_line(125, 135, 275, 135, width = 3, fill="blue")
1468 self.speedCanvas.create_arc(127, -60, 275, 133, extent=-180, style="arc", outline="blue")
1469 self.speedCanvas.create_text(100, 85, text = "s",font = LABELFONT, fill="blue")
1470 self.speedCanvas.create_text(200, 153, text = "t",font = LABELFONT, fill="blue")
1471
1472 self.velocityCanvas.create_text(200, 15, text = "Velocity - Time Graph",font = MEDIUMFONT, fill="red")
1473 self.velocityCanvas.create_line(125, 135, 125, 35, width = 3, fill="red")
1474 self.velocityCanvas.create_line(125, 85, 275, 85, width = 3, fill="red")
1475 self.velocityCanvas.create_line(125, 35, 275, 135, fill="red")
1476 self.velocityCanvas.create_text(100, 85, text = "v",font = LABELFONT, fill="red")
1477 self.velocityCanvas.create_text(295, 85, text = "t",font = LABELFONT, fill="red")
1478
1479 self.accelerationCanvas.create_text(200, 15, text = "Acceleration - Time Graph",font = MEDIUMFONT, fill="red")
1480 self.accelerationCanvas.create_line(125, 135, 125, 35, width = 3, fill="red")
1481 self.accelerationCanvas.create_line(125, 85, 275, 85, width = 3, fill="red")
1482 self.accelerationCanvas.create_line(125, 50, 275, 50, fill="red")
1483 self.accelerationCanvas.create_text(100, 85, text = "a",font = LABELFONT, fill="red")
1484 self.accelerationCanvas.create_text(295, 85, text = "t",font = LABELFONT, fill="red")
1485 self.accelerationCanvas.create_text(329, 49, text = "= 9.8 ms^-1",font = SMALLFONT, fill="red")
1486
1487 def returnForces():
1488 window.addScore(2)
1489 messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
1490 controller.show_frame(timeGraphsPage)
1491
1492# SUVAT Revision Pages #
1493
1494class SUVATRevisionPage(tk.Frame):
1495
1496 def __init__(self, parent, controller):
1497
1498 tk.Frame.__init__(self, parent)
1499 self.title = tk.Label(self, text="SUVAT Revision Page", font=LARGEFONT)
1500 self.title.pack(side="top", fill="x", pady=30)
1501
1502 self.SUVATCheckerButton = tk.Button(self, text = "SUVAT Checker", command=lambda: controller.show_frame(SUVATCheckerPage),height=2,width=20)
1503 self.label1 = tk.Label(self, text = "or ")
1504 self.SUVATSolverButton = tk.Button(self, text = "SUVAT Solver", command=lambda: controller.show_frame(SUVATSolverPage),height=2,width=20)
1505
1506 self.SUVATCheckerButton.pack(side="top", pady=5)
1507 self.label1.pack(side="top", fill="x", pady=5)
1508 self.SUVATSolverButton.pack(side="top", pady=5)
1509
1510class SUVATCheckerPage(tk.Frame):
1511
1512 def __init__(self, parent, controller):
1513
1514 tk.Frame.__init__(self, parent)
1515 self.title = tk.Label(self, text="SUVAT Checker Page", font=LARGEFONT)
1516 self.title.pack(padx=10, pady=10)
1517
1518 # Instructions explaining to the user what to enter into each entry field
1519 self.instructions = tk.Label(self, text = """You should have 3 known values, and an unknown value that you want to find
1520For each of the boxes below, either:
15211. The value is known so type it into the box
15222. The value is unknown and the value you want to find, type in 'A'
15233. The value is unknown and not the value you want to find, type in 'X'
1524
1525Enter your answer in the box by the check button (Please enter your answer to 2 decimal places. No units!)
1526A correct answer will earn you 10 points
1527An incorrect answer will lose you 1 point
1528""")
1529
1530 self.displacementText = tk.Label(self, text = "Displacement:")
1531 self.displacementInput = tk.Entry(self, justify="center", width=30)
1532
1533 self.initialVelocityText = tk.Label(self, text = "Initial Velocity:")
1534 self.initialVelocityInput = tk.Entry(self, justify="center", width=30)
1535
1536 self.finalVelocityText = tk.Label(self, text = "Final Velocity:")
1537 self.finalVelocityInput = tk.Entry(self, justify="center", width=30)
1538
1539 self.accelerationText = tk.Label(self, text = "Acceleration:")
1540 self.accelerationInput = tk.Entry(self, justify="center", width=30)
1541
1542 self.timeTakenText = tk.Label(self, text = "Time Taken:")
1543 self.timeTakenInput = tk.Entry(self, justify="center", width=30)
1544
1545 self.userAnswerText = tk.Label(self, text = "Your Answer: (Please enter your answer to 2 decimal places. No units!)\nSeparate dual answers with a single comma, no spaces!")
1546 self.userAnswerInput = tk.Entry(self, justify="center", width=30)
1547 self.submitButton = tk.Button(self,text = "Check", command=lambda: Solve())
1548
1549 self.instructions.pack(side="top", fill="x")
1550
1551 self.displacementText.pack(side="top", fill="x", padx=20, pady=5)
1552 self.displacementInput.pack(side="top")
1553 self.displacementInput.focus()
1554
1555 self.initialVelocityText.pack(side="top", fill="x", padx=20, pady=5)
1556 self.initialVelocityInput.pack(side="top")
1557
1558 self.finalVelocityText.pack(side="top", fill="x", padx=20, pady=5)
1559 self.finalVelocityInput.pack(side="top")
1560
1561 self.accelerationText.pack(side="top", fill="x", padx=20, pady=5)
1562 self.accelerationInput.pack(side="top")
1563
1564 self.timeTakenText.pack(side="top", fill="x", padx=20, pady=5)
1565 self.timeTakenInput.pack(side="top")
1566
1567 self.userAnswerText.pack(side="top", fill="x", padx=20, pady=5)
1568 self.userAnswerInput.pack(side="top", pady=5)
1569 self.submitButton.pack(side="bottom", fill="y", padx=20, pady=5)
1570
1571 def Solve():
1572
1573 def deleteEntryFields():
1574 self.displacementInput.delete(0,"end")
1575 self.initialVelocityInput.delete(0,"end")
1576 self.finalVelocityInput.delete(0,"end")
1577 self.accelerationInput.delete(0,"end")
1578 self.timeTakenInput.delete(0,"end")
1579
1580 def response(message1, message2, score, add):
1581 messagebox.showinfo("{0}".format(message1),"{0}".format(message2), icon = "info")
1582 if add:
1583 window.addScore(score)
1584 messagebox.showinfo("Score Updated","You earnt {0} points for beating PHYSICS".format(score), icon = "info")
1585 else:
1586 window.addScore(-score)
1587 messagebox.showinfo("Score Updated","You lost {0} points for losing to PHYSICS".format(score), icon = "info")
1588
1589 try:
1590 s = self.displacementInput.get().lower()
1591 except:
1592 s = self.displacementInput.get()
1593 try:
1594 u = self.initialVelocityInput.get().lower()
1595 except:
1596 u = self.initialVelocityInput.get()
1597 try:
1598 v = self.finalVelocityInput.get().lower()
1599 except:
1600 v = self.finalVelocityInput.get()
1601 try:
1602 a = self.accelerationInput.get().lower()
1603 except:
1604 a = self.accelerationInput.get()
1605 try:
1606 t = self.timeTakenInput.get().lower()
1607 except:
1608 t = self.timeTakenInput.get()
1609
1610 suvat = [s,u,v,a,t]
1611
1612 Xcount = 0
1613 Acount = 0
1614 numberCount = 0
1615 for each in suvat:
1616 if each.lower() == "x": # Increments
1617 Xcount += 1
1618 elif each.lower() == "a":
1619 Acount += 1
1620
1621 if each.isdigit(): # Used to ensure 3 values are numbers and stops the program crashing from attempting to convert letters into float numbers
1622 numberCount += 1
1623 elif "-" in each or "." in each:
1624 numberCount += 1
1625
1626 if "" in suvat:
1627 messagebox.showinfo("Error!","Leave no fields blank", icon="warning")
1628 elif Acount == 0:
1629 messagebox.showinfo("Error!","No value given as 'A'", icon="warning")
1630 elif Acount > 1:
1631 messagebox.showinfo("Error!","Only one value can be given as 'A'", icon="warning")
1632 elif Xcount == 0:
1633 messagebox.showinfo("Error!","No value given as 'X'", icon="warning")
1634 elif Xcount > 1:
1635 messagebox.showinfo("Error!","Only one value can be given as 'X'", icon="warning")
1636 elif numberCount != 3:
1637 messagebox.showinfo("Error!","Three values entered must be numbers", icon="warning")
1638 else:
1639 Solver = SUVAT(s,u,v,a,t,shortAnswer=True) # Calls the Solving algorithm, passing through the parameters given by the user
1640 # shortAnswer is True, so only the value is returned, no text
1641 answer = Solver.initiate() # Returns the answer(s) from the SUVAT equations
1642
1643 if answer == "None": # If an error occurs in the mathematics, 'None' is returned and this stops an error occuring
1644 messagebox.showinfo("Error","Invalid details inputted, try again", icon = "warning")
1645
1646 else:
1647 if answer == "zeroDivision error":
1648 messagebox.showinfo("Error","Invalid details inputted, resulting in a calculation involving a division by 0\n\nCheck your numbers", icon = "warning")
1649
1650 else:
1651 userAnswer = self.userAnswerInput.get()
1652
1653 if "," in userAnswer: # Comma suggests the answer has two parts, and so continues onto code that compares two answers
1654 userAnswer1, userAnswer2 = userAnswer.split(",") # Splits the answers into two variables
1655 answer1, answer2 = "{:.2f}".format(answer[0]), "{:.2f}".format(answer[1]) # Converts answers from SUVAT() into 2 decimal place variables
1656 userAnswer1, userAnswer2 = "{:.2f}".format(float(userAnswer1)), "{:.2f}".format(float(userAnswer2))
1657
1658 if userAnswer1 == answer1:
1659 if userAnswer2 == answer2:
1660 response("Correct!!", "You got both answers correct", 15, True)
1661 deleteEntryFields()
1662
1663 else: # First correct, second incorrect
1664 response("Incorrect!!", "Your second answer was wrong, try again", 1, False)
1665 self.userAnswerInput.delete(",","end")
1666
1667 else: # First answer is incorrect
1668 if userAnswer2 == answer2: #
1669 response("Incorrect!!", "Your first answer was wrong, try again", 1, False)
1670 self.userAnswerInput.delete(0,",")
1671
1672 else:
1673 if userAnswer1 == answer2:# If user enters dual answers in wrong order, compare opposite answers
1674 if userAnswer2 == answer1:
1675 response("Correct!!", "You got both answers correct", 15, True)
1676 deleteEntryFields()
1677
1678 else: # First answer correct, second incorrect
1679 response("Incorrect!!", "Your second answer was wrong, try again", 1, False)
1680 self.userAnswerInput.delete(0,",")
1681
1682 elif userAnswer2 == answer1:
1683 response("Incorrect!!", "Your first answer was wrong, try again", 1, False)
1684 self.userAnswerInput.delete(",","end")
1685
1686 else:
1687 response("Incorrect!!", "You got both answers wrong, try again", 2, False)
1688 self.userAnswerInput.delete(0,"end")
1689
1690 else: # No comma so only one part, so only us the first element in array 'answer'
1691 answer = "{0:.2f}".format(answer1)
1692 if userAnswer == answer:
1693 response("Correct!!", "You got the right answer!!", 10, True)
1694 deleteEntryFields()
1695
1696 else:
1697 response("Incorrect!!", "You entered the wrong answer", 1, False)
1698 self.userAnswerInput.delete(0,"end")
1699
1700class SUVATSolverPage(tk.Frame):
1701
1702 def __init__(self, parent, controller):
1703
1704 tk.Frame.__init__(self, parent)
1705 self.title = tk.Label(self, text="SUVAT Solver Page", font=LARGEFONT)
1706 self.title.pack(padx=10, pady=10)
1707
1708 self.instructions = tk.Label(self, text = """You should have 3 known values, and an unknown value that you want to find
1709For each of the boxes below, either:
17101. The value is known so type it into the box
17112. The value is unknown and the value you want to find, type in 'A'
17123. The value is unknown and not the value you want to find, type in 'X'
1713
1714Warning!!! Every answer you seek from this tool with remove 5 points from your account!
1715""")
1716
1717 self.displacementText = tk.Label(self, text = "Displacement:")
1718 self.displacementInput = tk.Entry(self, justify="center", width=30)
1719
1720 self.initialVelocityText = tk.Label(self, text = "Initial Velocity:")
1721 self.initialVelocityInput = tk.Entry(self, justify="center", width=30)
1722
1723 self.finalVelocityText = tk.Label(self, text = "Final Velocity:")
1724 self.finalVelocityInput = tk.Entry(self, justify="center", width=30)
1725
1726 self.accelerationText = tk.Label(self, text = "Acceleration:")
1727 self.accelerationInput = tk.Entry(self, justify="center", width=30)
1728
1729 self.timeTakenText = tk.Label(self, text = "Time Taken:")
1730 self.timeTakenInput = tk.Entry(self, justify="center", width=30)
1731
1732 self.submitButton = tk.Button(self,text = "Solve", command=lambda: Solve())
1733
1734 self.instructions.pack(side="top", fill="x", pady=15)
1735
1736 self.displacementText.pack(side="top", fill="x", padx=20, pady=5)
1737 self.displacementInput.pack(side="top")
1738 self.displacementInput.focus()
1739
1740 self.initialVelocityText.pack(side="top", fill="x", padx=20, pady=5)
1741 self.initialVelocityInput.pack(side="top")
1742
1743 self.finalVelocityText.pack(side="top", fill="x", padx=20, pady=5)
1744 self.finalVelocityInput.pack(side="top")
1745
1746 self.accelerationText.pack(side="top", fill="x", padx=20, pady=5)
1747 self.accelerationInput.pack(side="top")
1748
1749 self.timeTakenText.pack(side="top", fill="x", padx=20, pady=5)
1750 self.timeTakenInput.pack(side="top")
1751
1752 self.submitButton.pack(side="top", fill="y", padx=20, pady=10)
1753
1754 def Solve():
1755
1756 # Validation Statements
1757
1758 try:
1759 s = self.displacementInput.get().lower()
1760 except:
1761 s = self.displacementInput.get()
1762 try:
1763 u = self.initialVelocityInput.get().lower()
1764 except:
1765 u = self.initialVelocityInput.get()
1766 try:
1767 v = self.finalVelocityInput.get().lower()
1768 except:
1769 v = self.finalVelocityInput.get()
1770 try:
1771 a = self.accelerationInput.get().lower()
1772 except:
1773 a = self.accelerationInput.get()
1774 try:
1775 t = self.timeTakenInput.get().lower()
1776 except:
1777 t = self.timeTakenInput.get()
1778
1779 suvat = [s,u,v,a,t]
1780
1781 Xcount = 0
1782 Acount = 0
1783 numberCount = 0
1784 for each in suvat:
1785 if each.lower() == "x":
1786 Xcount += 1
1787 elif each.lower() == "a":
1788 Acount += 1
1789
1790 if each.isdigit(): # Used to ensure 3 values are numbers and stops the program crashing from attempting to convert letters into float numbers
1791 numberCount += 1
1792 elif "-" in each or "." in each:
1793 numberCount += 1
1794
1795 if "" in suvat:
1796 messagebox.showinfo("Error!","Leave no fields blank", icon="warning")
1797 elif Acount == 0:
1798 messagebox.showinfo("Error!","No value given as 'A'", icon="warning")
1799 elif Acount > 1:
1800 messagebox.showinfo("Error!","Only one value can be given as 'A'", icon="warning")
1801 elif Xcount == 0:
1802 messagebox.showinfo("Error!","No value given as 'X'", icon="warning")
1803 elif Xcount > 1:
1804 messagebox.showinfo("Error!","Only one value can be given as 'X'", icon="warning")
1805 elif numberCount != 3:
1806 messagebox.showinfo("Error!","Three values entered must be numbers", icon="warning")
1807 else:
1808 Solver = SUVAT(s,u,v,a,t,shortAnswer=False) # Calls the Solving algorithm, passing through the parameters given by the user, shortAnswer=False means worded solution returned
1809 answer = Solver.initiate()
1810 if answer == "None":
1811 messagebox.showinfo("Error","Invalid values inputted, try again", icon = "warning")
1812
1813 else:
1814 if answer == "zeroDivision error":
1815 messagebox.showinfo("Error","Invalid details inputted, resulting in a calculation involving a division by 0\n\nCheck your numbers", icon = "warning")
1816
1817 else:
1818 messagebox.showinfo("Answer","{0}".format(answer), icon = "info")
1819 window.addScore(-5)
1820 messagebox.showinfo("Score Updated","You lost 5 points for cheating PHYSICS by just wanting an answer", icon = "info")
1821 deleteEntryFields()
1822
1823
1824 def deleteEntryFields():
1825 self.displacementInput.delete(0,"end")
1826 self.initialVelocityInput.delete(0,"end")
1827 self.finalVelocityInput.delete(0,"end")
1828 self.accelerationInput.delete(0,"end")
1829 self.timeTakenInput.delete(0,"end")
1830
1831#############################
1832
1833
1834
1835
1836
1837##### Tkinter Runtime #####
1838
1839def exitProgram():
1840 if messagebox.askokcancel("Quit", "Do you wish to quit?"):
1841 window.logout()
1842 window.destroy()
1843
1844if runProgram: # If any python modules are missing, the Tkinter window will not be called and the program will cease
1845 window = GUI()
1846 window.protocol("WM_DELETE_WINDOW", exitProgram) # If 'x' in top right corner of GUI window pressed, call exitProgram()
1847 window.mainloop()
1848
1849###########################