Advertisement
Guest User

NEA Code

a guest
Mar 31st, 2017
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 86.95 KB | None | 0 0
  1. # NEA
  2. # Andrew Howell Candidate No. 0082
  3. # St. John Payne School Centre No. 16331
  4.  
  5. runProgram = True
  6.  
  7. ##### Importing Python Modules needed for program #####
  8.  
  9. # Defensive programming - catching exceptions in code where python modules are not present
  10. try:
  11.   import tkinter as tk
  12.   from tkinter import messagebox
  13.   from tkinter import *
  14. except:
  15.   print("Python's Tkinter module not installed, Program cannot run")
  16.   runProgram = False
  17.  
  18. try:
  19.   import pickle
  20. except:
  21.   messagebox.showinfo("Error","Python's Pickle module not installed, Program cannot run")
  22.   runProgram = False
  23.  
  24. try:
  25.   import datetime
  26. except:
  27.   messagebox.showinfo("Error","Python's Datetime module not installed, Program cannot run")
  28.   runProgram = False
  29.  
  30. try:
  31.   import math
  32. except:
  33.   messagebox.showinfo("Error","Python's Datetime module not installed, Program cannot run")
  34.   runProgram = False
  35.  
  36. try:
  37.   import random
  38. except:
  39.   messagebox.showinfo("Error","Python's Random module not installed, Program cannot run")
  40.   runProgram = False
  41.  
  42. try:
  43.   import passlib
  44.   from passlib.hash import pbkdf2_sha256
  45. except:
  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
  58. HASHEDADMINPASSWORD = "$pbkdf2-sha256$29000$COH8X8sZQ6j1PkeoFUIIQQ$64MnDDlriVWgZGjjXEHP/HnlweMr/OkbAmAvgUGYDoA"
  59.  
  60. ADMIN = ["Admin", HASHEDADMINPASSWORD] # Admin details
  61.  
  62. LARGEFONT = ("Verdana", 22) # Font format for titles on each page
  63. MEDIUMFONT = ("Verdana", 16)
  64. LABELFONT = ("Verdana", 13)
  65. SMALLFONT = ("Verdana", 11)
  66.  
  67. # Dimensions of the Tkinter window
  68. WIDTH = 800
  69. HEIGHT = 600
  70.  
  71. FILENAME = "NEADatabase.dat" # Constant database name
  72.  
  73. ################################
  74.  
  75.  
  76.  
  77.  
  78.  
  79. ##### File Handling #####
  80.  
  81. #Username Format: USERNAMES[Username] = [Password, Score, LastSession]
  82. USERNAMES = {} # Dictionary where student details will be stored whilst the program runs
  83. try:
  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
  88. except EOFError:
  89.   pass
  90.  
  91. def 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.  
  102. def Modulus(a):
  103.     if a < 0:
  104.         a = -a
  105.     return a
  106.  
  107. def 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.  
  140. def 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.  
  156. class 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
  394. class 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.  
  495. class 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.  
  515. class 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.  
  550. class 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.  
  600. class 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.  
  642. class 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.  
  736. class 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.  
  778. class 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.      
  819. class 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.  
  843. class 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.  
  867. class 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.  
  919. class 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
  947. to add vectors by calculation
  948. with vectors at right angles
  949.  
  950. Therefore, addition of vectors
  951. by calculation simply requires
  952. Pythagoras'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
  959. after travelling along two vectors
  960.  
  961. In which case, substitute in 'a' and 'b'
  962. and rearrange to find 'c'
  963. which will be your vector's magnitude
  964. Use trigonometry to find
  965. the 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.  
  972. class 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
  1000. by scale drawing
  1001.  
  1002. The angle between these vectors is
  1003. NOT limited to right angles
  1004.  
  1005. You must draw the vectors
  1006. to 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.  
  1034. class 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
  1055. by calculation
  1056.  
  1057. Every vector has a vertical
  1058. and horizontal component
  1059.  
  1060. Simply add the two components
  1061. in order to find the vector's
  1062. magnitude""", 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.  
  1092. class 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.  
  1161. class 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
  1217. and your values of weight, support and friction to find Θ
  1218.  
  1219. As the triangle's overall displacement is zero,
  1220. an unknown weight, support or friction force
  1221. will be equal to the negative sum of the
  1222. known values
  1223. e.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.  
  1233. class 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.  
  1251. class 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.  
  1331. class 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.  
  1411. class 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.  
  1494. class 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.  
  1510. class 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
  1520. For each of the boxes below, either:
  1521. 1. The value is known so type it into the box
  1522. 2. The value is unknown and the value you want to find, type in 'A'
  1523. 3. The value is unknown and not the value you want to find, type in 'X'
  1524.  
  1525. Enter your answer in the box by the check button (Please enter your answer to 2 decimal places. No units!)
  1526. A correct answer will earn you 10 points
  1527. An 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.    
  1700. class 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
  1709. For each of the boxes below, either:
  1710. 1. The value is known so type it into the box
  1711. 2. The value is unknown and the value you want to find, type in 'A'
  1712. 3. The value is unknown and not the value you want to find, type in 'X'
  1713.  
  1714. Warning!!! 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.  
  1839. def exitProgram():
  1840.   if messagebox.askokcancel("Quit", "Do you wish to quit?"):
  1841.     window.logout()
  1842.     window.destroy()
  1843.  
  1844. if 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. ###########################
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement