Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # NEA
- # Andrew Howell Candidate No. 0082
- # St. John Payne School Centre No. 16331
- runProgram = True
- ##### Importing Python Modules needed for program #####
- # Defensive programming - catching exceptions in code where python modules are not present
- try:
- import tkinter as tk
- from tkinter import messagebox
- from tkinter import *
- except:
- print("Python's Tkinter module not installed, Program cannot run")
- runProgram = False
- try:
- import pickle
- except:
- messagebox.showinfo("Error","Python's Pickle module not installed, Program cannot run")
- runProgram = False
- try:
- import datetime
- except:
- messagebox.showinfo("Error","Python's Datetime module not installed, Program cannot run")
- runProgram = False
- try:
- import math
- except:
- messagebox.showinfo("Error","Python's Datetime module not installed, Program cannot run")
- runProgram = False
- try:
- import random
- except:
- messagebox.showinfo("Error","Python's Random module not installed, Program cannot run")
- runProgram = False
- try:
- import passlib
- from passlib.hash import pbkdf2_sha256
- except:
- messagebox.showinfo("Error","Python's Passlib module not installed, Program cannot run")
- runProgram = False
- try:
- import matplotlib
- matplotlib.use("TkAgg")
- from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
- from matplotlib.figure import Figure
- import matplotlib.animation as animation
- from matplotlib import style
- except:
- messagebox.showinfo("Error","Python's Matplotlib module not installed, Program cannot run")
- runProgram = False
- try:
- import numpy as np
- except:
- messagebox.showinfo("Error","Python's NumPy module not installed, Program cannot run")
- runProgram = False
- #######################################################
- ##### Constant Declaration #####
- # Using passlib's hashing algorithm, password is securely encrypted
- HASHEDADMINPASSWORD = "$pbkdf2-sha256$29000$COH8X8sZQ6j1PkeoFUIIQQ$64MnDDlriVWgZGjjXEHP/HnlweMr/OkbAmAvgUGYDoA"
- ADMIN = ["Admin", HASHEDADMINPASSWORD] # Admin details
- LARGEFONT = ("Verdana", 22) # Font format for titles on each page
- MEDIUMFONT = ("Verdana", 16)
- LABELFONT = ("Verdana", 13)
- SMALLFONT = ("Verdana", 11)
- # Dimensions of the Tkinter window
- WIDTH = 800
- HEIGHT = 600
- FILENAME = "NEADatabase.dat" # Constant database name
- # Graph style
- style.use("ggplot")
- # Tkinter window RGB value
- BGCOLOUR = "#f0f0f0"
- ################################
- ##### File Handling #####
- # Using pickle because pickle allows a dictionary to be pickled directly to and from a file
- # Other file handling methods would need the dictionary to be broken down and then saved,
- # and when read, the dictionary would have to be manually reconstructed
- # Pickle makes file handling much simpler and faster and more efficient
- #Username Format: USERNAMES[Username] = [Password, Score, LastSession]
- USERNAMES = {} # Dictionary where student details will be stored whilst the program runs
- try:
- try:
- USERNAMES = pickle.load(open(FILENAME, "rb")) # Retrieves dictionary of user details stored in database
- except:
- pickle.dump({},open(FILENAME, "wb")) # If database not present in directory, create file
- except EOFError:
- pass
- def saveUsers(): # Writes the current dictionary of user details to the database
- pickle.dump(USERNAMES, open(FILENAME, "wb"))
- #########################
- ##### Mathematical Operational Functions #####
- def Modulus(a): # Checks if the arguement is negative
- if a < 0: # If so...
- a = -a # Make it positive (negative of a negative is a positive)
- return a # Returns positive number
- def mergeSort(alist): # A list is passed into the function
- if len(alist) > 1: # Only performs splitting section of algorithm if the list is bigger than one element
- mid = len(alist)//2 # Finds integer index position of middle element
- lefthalf = alist[:mid] # Creates lists for first and second half of 'alist'
- righthalf = alist[mid:] # Using [:mid] does not include the element in the 'mid' position so lists do not overlap
- mergeSort(lefthalf) # Recursive calls
- mergeSort(righthalf) # Continues to split lists until they containt only one element
- leftHalfPosition = 0 # Starting position of pointer in left list
- rightHalfPosition = 0 # Starting position of pointer in right list
- newListPosition = 0 # Starting position in new merged list that will be sorted
- while leftHalfPosition < len(lefthalf) and rightHalfPosition < len(righthalf): # If pointers are still in both lists
- if lefthalf[leftHalfPosition] < righthalf[rightHalfPosition]: # Compares pointers in each list. If left list element is smaller...
- alist[newListPosition] = lefthalf[leftHalfPosition] # Append that left list element to the new list
- leftHalfPosition += 1 # Move left list pointer along one
- else: # If right list element is smaller...
- alist[originalListPosition] = righthalf[rightHalfPosition] # Append that right list element to the new list
- rightHalfPosition += 1 # Move right list pointer along one
- newListPosition += 1 # No matter which is smaller, new list will have one more element so move pointer along
- while leftHalfPosition < len(lefthalf): # Right list elements exhausted, so only left list pointer still in list...
- alist[newListPosition] = lefthalf[leftHalfPosition] # Append that left list element to the new list
- leftHalfPosition += 1 # Move left list pointer along one
- newListPosition += 1 # Move new list pointer along one
- while rightHalfPosition < len(righthalf): # Left list elements exhausted, so only right list pointer still in list...
- alist[newListPosition] = righthalf[rightHalfPosition] # Append that right list element to the new list
- rightHalfPosition += 1 # Move right list pointer along one
- newListPosition += 1 # Move new list pointer along one
- return alist # Returns the newly merged list
- def getCurrentDate(): # Returns array of current day, month and year
- day = datetime.date.today().day
- month = datetime.date.today().month
- year = datetime.date.today().year
- date = [day, month, year]
- return date
- def areaUnderCurve(xValues, yValues): # Two lists passed in as arguements
- # Uses Trapezium Rule
- # Area = 0.5h(y0 + yn + 2(y1 + y2 + ... + yn-1))
- # As this is not a curve, but rather composed of straight lines, this algorithm will produce an accurate result
- # Whereas ussually the trapezium rule only produces an estimate
- if len(xValues) > 1 and len(yValues) > 1: # Algorithm needs lists longer than one element
- n = len(yValues) - 1 # n is the number of 'gaps' between each vertical height line
- h = (xValues[-1] - xValues[0])/n # h is the width of those gaps
- ySubTotal = 0 # Variable that will store total of y values from y1 to yn-1
- for each in yValues[1:-1]: # Refers to all elements in the yValues list that are between position 1 and position n-1
- ySubTotal += each # Adds this y value to the total
- area = 0.5*h*( (yValues[0] + yValues[-1]) + 2*ySubTotal ) # Trapezium rule equation
- return area # Returns this newly found area
- else: # If lists are not longer than 1, algorithm cannot run, so...
- messagebox.showinfo("Error", "Not enough values given to find area under curve", icon="warning") # INform the user the algorithm needs more data
- return "N/A"
- ##############################################
- ##### SUVAT Equation Solving Algorithm #####
- # This class is an example of polymorphism
- # Polymorphism is the method of using a single class to create many different objects performing different tasks
- # Each instantiation of the SUVAT object performs differently, calling different methods based on the arguements given
- class SUVAT():
- def __init__(self,s,u,v,a,t,shortAnswer):
- # Passes parameters from user as attributes
- self.s = s
- self.u = u
- self.v = v
- self.a = a
- self.t = t
- self.sA = shortAnswer # Boolean - determines whether object returns worded answer or just numeric answer
- try:
- def initiate(self): # Determines which method (and therefore which SUVAT eqaution) to call based on which parameters are 'x'
- if self.s == "x":
- return self.SUVAT1()
- elif self.u == "x":
- return self.SUVAT2()
- elif self.v == "x":
- return self.SUVAT3()
- elif self.a == "x":
- return self.SUVAT4()
- elif self.t == "x":
- return self.SUVAT5()
- except:
- messagebox.showinfo("Error","Invalid details inputted, try again", icon = "warning")
- def SUVAT1(self): # v = u + at (s = 'X')
- if self.u == "a":
- self.u = float(self.v) - float(self.a)*float(self.t) # Converts string parameters given by user to a float value
- if self.sA: # If the user wants a short answer -> using Checker not Solver
- return [self.u,0] # Some calculations return two values so a 2 element array is returned
- else:
- return("Initial Velocity is {0:.2f} ms^-1".format(self.u))
- elif self.v == "a":
- self.v = float(self.u) + float(self.a)*float(self.t)
- if self.sA:
- return [self.v,0]
- else:
- return("Final Velocity is {0:.2f} ms^-1".format(self.v))
- elif self.a == "a":
- if float(self.t) == 0:
- return "zeroDivision error"
- else:
- self.a = (float(self.v) - float(self.u))/float(self.t)
- if self.sA:
- return [self.a,0]
- else:
- return("Acceleration is {0:.2f} ms^-2".format(self.a))
- elif self.t == "a":
- if float(self.a) == 0:
- return "zeroDivision error" # Calculation would include a division by zero which creates an error and so
- # validation will inform the user that the question cannot include a division by zero
- else:
- self.t = (float(self.v) - float(self.u))/float(self.a)
- if self.sA:
- return [self.t,0]
- else:
- return("Time Taken is {0:.2f} s".format(self.t))
- def SUVAT2(self): # s = vt - 0.5at^2 (u = 'X')
- if self.s == "a":
- self.s = float(self.v)*float(self.t) - 0.5*float(self.a)*float(self.t)**2
- if self.sA:
- return [self.s,0]
- else:
- return("Displacement is {0:.2f} m".format(self.s))
- elif self.v == "a":
- if float(self.t) == 0:
- return "zeroDivision error"
- else:
- self.v = float(self.s)/float(self.t) + 0.5*float(self.a)*float(self.t)
- if self.sA:
- return [self.v,0]
- else:
- return("Final Velocity is {0:.2f} ms^-1".format(self.v))
- elif self.a == "a":
- if float(self.t) == 0:
- return "zeroDivision error"
- else:
- self.a = (float(self.v)*float(self.t) - float(self.s))/(0.5*float(self.t)**2)
- if self.sA:
- return [self.a,0]
- else:
- return("Acceleration is {0:.2f} ms^-2".format(self.a))
- elif self.t == "a":
- if float(self.a) == 0:
- return "zeroDivision error"
- else:
- x = float(self.v)**2 - 2*float(self.a)*float(self.s)
- x = Modulus(x)
- x = math.sqrt(x)
- t1 = ((float(self.v) + (x))/float(self.a))
- t2 = ((float(self.v) - (x))/float(self.a))
- if self.sA:
- return [t1,t2] # Two values of t
- else:
- return("Time Taken is {0:.2f} s and {1:.2f} s".format(t1, t2))
- def SUVAT3(self): # s = ut + 0.5at^2 (v = 'X')
- if self.s == "a":
- self.s = float(self.u)*float(self.t) + 0.5*float(self.a)*float(self.t)**2
- if self.sA:
- return [self.s,0]
- else:
- return("Displacement is {0:.2f} m".format(self.s))
- elif self.u == "a":
- if float(self.t) == 0:
- return "zeroDivision error"
- else:
- self.u = float(self.s)/float(self.t) - 0.5*float(self.a)*float(self.t)
- if self.sA:
- return [self.u,0]
- else:
- return("Initial Velocity is {0:.2f} ms^-1".format(self.u))
- elif self.a == "a":
- if float(self.t) == 0:
- return "zeroDivision error"
- else:
- self.a = (float(self.s) - float(self.u)*float(self.t))/(0.5*float(self.t)**2)
- if self.sA:
- return [self.a,0]
- else:
- return("Acceleration is {0:.2f} ms^-2".format(self.a))
- elif self.t == "a":
- if float(self.a) == 0:
- return "zeroDivision error"
- else: # Using quadratic equation - returns two values of t
- x = float(self.u)**2 + 2*float(self.a)*float(self.s)
- x = Modulus(x)
- x = math.sqrt(x)
- t1 = ((-float(self.u) + (x))/float(self.a))
- t2 = ((-float(self.u) - (x))/float(self.a))
- if self.sA:
- return [t1,t2]
- else:
- return("Time Taken is {0:.2f} s and {1:.2f} s".format(t1, t2))
- def SUVAT4(self): # s = 0.5(u + v)t (a = 'X')
- if self.s == "a":
- self.s = 0.5*(float(self.u) + float(self.v))*float(self.t)
- if self.sA:
- return [self.s,0]
- else:
- return("Displacement is {0:.2f} m".format(self.s))
- elif self.u == "a":
- if float(self.t) == 0:
- return "zeroDivision error"
- else:
- self.u = (2*float(self.s))/float(self.t) - float(self.v)
- if self.sA:
- return [self.u,0]
- else:
- return("Initial Velocity is {0:.2f} ms^-1".format(float(self.u)))
- elif self.v == "a":
- if float(self.t) == 0:
- return "zeroDivision error"
- else:
- self.v = (2*float(self.s))/float(self.t) - float(self.u)
- if self.sA:
- return [self.v,0]
- else:
- return("Final Velocity is {0:.2f} ms^-1".format(self.v))
- elif self.t == "a":
- if (float(self.u) + float(self.v)) == 0:
- return "zeroDivision error"
- else:
- self.t = (2*float(self.s))/(float(self.u) + float(self.v))
- if self.sA:
- return [self.t,0]
- else:
- return("Time Taken is {0:.2f} s".format(self.t))
- def SUVAT5(self): # v^2 = u^2 + 2as (t = 'X')
- if self.s == "a":
- if float(self.a) == 0:
- return "zeroDivision error"
- else:
- self.s = (float(self.v)**2 - float(self.u)**2)/2*float(self.a)
- if self.sA:
- return [self.s,0]
- else:
- return("Displacement is {0:.2f} m".format(self.s))
- elif self.u == "a":
- uSquared = float(self.v)**2 - 2*float(self.a)*float(self.s)
- self.u = math.sqrt(Modulus(uSquared)) # If self.u is negative,
- # square rooting it will cause
- # an error, so we square root the modulus
- if self.sA:
- return [self.u,-self.u]
- else:
- return("Initial Velocity is {0:.2f} ms^-1 and {1:.2f} ms^-1".format(self.u,-self.u))
- elif self.v == "a":
- vSquared = float(self.u)**2 + 2*float(self.a)*float(self.s)
- self.v = math.sqrt(Modulus(vSquared))
- if self.sA:
- return [self.v,-self.v]
- else:
- return("Final Velocity is {0:.2f} ms^-1 and {1:.2f} ms^-1".format(self.v,-self.v))
- elif self.a == "a":
- if float(self.s) == 0:
- return "zeroDivision error"
- else:
- self.a = (float(self.v)**2 - float(self.u)**2)/2*float(self.s)
- if self.sA:
- return [self.a,0]
- else:
- return("Acceleration is {0:.2f} ms^-2".format(self.a))
- ############################################
- ##### Matplotlib Animation Function #####
- # Creates the backend of the graph
- f = Figure(figsize=(8,6), dpi=80)
- a = f.add_subplot(111)
- a.axhline(linewidth=0.5, color="k")
- a.axvline(linewidth=0.5, color="k")
- a.set_title("Distance-Time Graph")
- a.set_ylabel('distance /m')
- a.set_xlabel('time /s')
- # An example of composition
- # This class is used as a repository for all the information contained within the graph
- # The GraphController class within the interactiveGraphsPage class utilises this class
- # It holds the current state of the graph in its attributes and its methods alter those attributes
- class animationObject():
- def __init__(self):
- self.play = False
- self.title = "Distance-Time Graph"
- self.ylabel = "distance /m"
- self.xlabel = "time /s"
- self.xCounter = 1 # X coordinate, simply increments by 1 every time that the ainmate function is called
- self.xList = [0] # X coordinates of points on the graph
- self.yList = [0] # Y coordinates of points on the graph
- def changeState(self): # Changes state, from paused to running, or vice versa
- if self.play == False:
- self.play = True
- elif self.play == True:
- self.play = False
- def gradientUnits(self): # Calculates units from the current graphs y axis label
- yUnit = self.ylabel.split("/")[1] # Splits the ylabel into an array, the letters after '/' are stored in yUnit
- if yUnit == "m": # Gradient will be the y unit divided by time
- return "ms^-1" # So if the y unit is metres, the gradient will be metres per second or ms^-1
- if yUnit == "ms^-1":
- return "ms^-2"
- if yUnit == "ms^-2":
- return "ms^-3"
- def areaUnits(self): # Calculates units from the current graphs y axis label
- yUnit = self.ylabel.split("/")[1] # Splits the ylabel into an array, the letters after '/' are stored in yUnit
- if yUnit == "m": # Area will be the y unit mulitplied by time
- return "ms" # So if the y unit is metres, the area will be metre seconds or ms
- if yUnit == "ms^-1":
- return "m"
- if yUnit == "ms^-2":
- return "ms^-1"
- animationState = animationObject()
- # Animate function is called every half second, it updates the backend of the graph
- def animate(i):
- a.axhline(linewidth=0.5, color="k")
- a.axvline(linewidth=0.5, color="k")
- a.set_title(animationState.title)
- a.set_ylabel(animationState.ylabel)
- a.set_xlabel(animationState.xlabel)
- if animationState.play == True: # Only if the user has told the program to run the graph, will it update / animate
- xList = animationState.xList
- yList = animationState.yList
- # Distance and Speed graphs are scalar and cannot be negative
- # This if statement stops the graph from updating if it is going to become zero and it is one of these scalar graphs
- if yList[int((animationState.xCounter)-1)] + window.frames[interactiveGraphsPage].graphController.gradientScale.get() < 0 and "distance" in animationState.ylabel or "speed" in animationState.ylabel:
- animationState.changeState()
- window.frames[interactiveGraphsPage].graphController.currentState.configure(text="Graph is: Paused")
- messagebox.showinfo("Warning","Graphs of this type cannot be negative\n\nDistance and Speed are Scalar Quantities\n\nScalar Quantities cannot be negative", icon="warning")
- window.frames[interactiveGraphsPage].graphController.gradientScale.set(0)
- else: # If the graph can continue, it updates the lists of coordinates and creates the new graph
- yList.append(yList[int((animationState.xCounter)-1)] + window.frames[interactiveGraphsPage].graphController.gradientScale.get())
- xList.append(animationState.xCounter)
- a.clear()
- a.plot(xList, yList)
- a.axhline(linewidth=0.5, color="k")
- a.axvline(linewidth=0.5, color="k")
- a.set_title(animationState.title)
- a.set_ylabel(animationState.ylabel)
- a.set_xlabel(animationState.xlabel)
- animationState.xCounter = animationState.xCounter + 1
- #########################################
- ##### GUI Classes #####
- # Another example of composition
- # GUI class uses Tkinter's Frames as pages in the Tkinter window
- # Each of these Frames are objects instantiated from the child classes
- class GUI(tk.Tk):
- def __init__(self, *args, **kwargs): # Allows a variable amount of keyworded and non-keyworded arguements to be passed into the object
- self.activeUser = "" # Stores the Username of a current user
- tk.Tk.__init__(self, *args, **kwargs)
- tk.Tk.iconbitmap(self, default="NEALogo.ico") # Displays telescope icon to be displayed in left-hand corner of the GUI window
- tk.Tk.wm_title(self, "Physics Learning Aid") # Displays on the header of th GUI window
- container = tk.Frame(self) # Container holds all elements of the frames and the toolbar
- container.pack(side="top", fill="both", expand = True)
- container.grid_rowconfigure(0, weight=1) # Weight attribute added to allow the rows and colunmns to display properly
- container.grid_columnconfigure(0, weight=1)
- menubar = tk.Menu(container) # Creates the toolbar where students can easily access different pages
- self.filemenu = tk.Menu(menubar, tearoff=0)
- self.filemenu.add_command(label="Home", state="disable", command = lambda: self.show_frame(homePage)) # Pages disabled until a user logs in
- self.filemenu.add_command(label="1: Forces", state="disable", command = lambda: self.show_frame(forcesPage))
- self.filemenu.add_command(label="2: Time Graphs", state="disable", command = lambda: self.show_frame(timeGraphsPage))
- self.filemenu.add_command(label="3. SUVAT Revision", state="disable", command = lambda: self.show_frame(SUVATRevisionPage))
- self.filemenu.add_command(label="Account", command = lambda: self.show_frame(accountPage))
- helpmenu = tk.Menu(self.filemenu, tearoff=0) # Dropdown menu
- helpmenu.add_command(label="General Help", command=self.helpme)
- helpmenu.add_command(label="Application Help", command=self.helpme)
- helpmenu.add_command(label="SUVAT Solver Help", command=self.helpme)
- self.filemenu.add_cascade(label="Help", menu=helpmenu)
- tk.Tk.config(self, menu=self.filemenu)
- self.frames = {}
- # Creates each individual page as an object is instanciated from the page classes
- for page in (startPage, accountPage, changePasswordPage, loginPage, signupPage, adminLoginPage, adminPage, homePage, forcesPage, ScalarsVectorsPage, AdditionVectorsCalculationPage,
- AdditionVectorsScaleDrawingPage, ResolutionOfVectorsPage, InclinedPlaneVectorsPage, VectorsInEquilibriumPage, timeGraphsPage, GradientsPage, AreaUnderCurvePage, BouncingBallPage,
- interactiveGraphsPage, SUVATRevisionPage, SUVATCheckerPage, SUVATSolverPage):
- frame = page(container, self)
- self.frames[page] = frame
- frame.grid(row=0, column=0, sticky="nsew")
- self.centreScreen(WIDTH, HEIGHT)
- def helpme(self):
- 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",
- "I'm in the Bahamas on holiday right now\n\nLEAVE\n\nME\n\nALONE"]
- helpChoice = random.randrange(len(helpList))
- helpComment = helpList[helpChoice-1]
- messagebox.showinfo("Help Bot","Hi, you have requested help\n\n{}".format(helpComment), icon="info")
- def enableWidgets(self):
- self.filemenu.entryconfig("Home", state="normal")
- self.filemenu.entryconfig("1: Forces", state="normal")
- self.filemenu.entryconfig("2: Time Graphs", state="normal")
- self.filemenu.entryconfig("3. SUVAT Revision", state="normal")
- def disableWidgets(self):
- self.filemenu.entryconfig("Home", state="disable")
- self.filemenu.entryconfig("1: Forces", state="disable")
- self.filemenu.entryconfig("2: Time Graphs", state="disable")
- self.filemenu.entryconfig("3. SUVAT Revision", state="disable")
- def addScore(self, score):
- if window.activeUser != "Admin" and window.activeUser != "":
- USERNAMES[self.activeUser][1] += score
- def centreScreen(self, w, h): # Uses screen dimensions to centre the GUI window
- ws = self.winfo_screenwidth()
- hs = self.winfo_screenheight()
- # Finds the top left coordinate that the GUI will be in order to be centered
- x = (ws / 2) - (w / 2)
- y = (hs / 2) - (w / 2)
- # Align window with the top left coordinate
- self.geometry("%dx%d+%d+%d" % (w, h, x, y)) # takes parameters as 'wxh+x+y'
- self.resizable(width=False, height=False)
- # Sets page that program will start with
- self.show_frame(startPage)
- def logout(self):
- if self.activeUser != "" and self.activeUser != ADMIN[0]:
- date = getCurrentDate()
- USERNAMES[self.activeUser][2] = date
- self.activeUser = ""
- self.disableWidgets()
- messagebox.showinfo("Logged out", "You have been logged out successfully")
- saveUsers()
- self.show_frame(startPage)
- def show_frame(self, cont):
- frame = self.frames[cont]
- if cont.__name__ != "interactiveGraphsPage": # Checks if the new page to be displayed is not called 'interactiveGraphsPage'
- try:
- self.frames[interactiveGraphsPage].graphController.destroy() # If it is, try to destroy the graph controller window
- except: # The except statement will run if the graph controller window is not open
- pass # In which case, ignore and continue
- frame.tkraise() # When called it raises the given page to the top of the GUI
- ### Start of Page Classes ###
- class startPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Start Page", font=LARGEFONT)
- self.title.pack(side="top", fill="x", pady=30)
- self.welcomeMsg = tk.Label(self, text = "Welcome to the Physics Learning Aid!")
- self.label1 = tk.Label(self, text = "Are you a")
- self.student = tk.Button(self, text = "Student", command=lambda: controller.show_frame(accountPage),height=2,width=20)
- self.label2 = tk.Label(self, text = "or ")
- self.teacher = tk.Button(self, text = "Teacher", command=lambda: controller.show_frame(adminLoginPage),height=2,width=20)
- self.welcomeMsg.pack(side="top", fill="x", padx=5, pady=20)
- self.label1.pack(side="top", fill="x", pady=5)
- self.student.pack(side="top", pady=5)
- self.label2.pack(side="top", fill="x", pady=5)
- self.teacher.pack(side="top", pady=5)
- class accountPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Account Page", font=LARGEFONT)
- self.title.pack(side="top", fill="x", pady=30)
- self.login = tk.Button(self, text = "Existing User - Log in", command=lambda: controller.show_frame(loginPage),height=2,width=20)
- self.signUp = tk.Button(self, text = "New User - Sign Up", command=lambda: controller.show_frame(signupPage),height=2,width=20)
- self.logoutButton = tk.Button(self, text = "Log out", command=lambda: window.logout())
- self.selectButton = tk.Button(self,text = "Score", command=lambda: showScore())
- self.changePasswordButton = tk.Button(self, text = "Change Password", command=lambda: changePassword())
- self.login.pack(side="top", fill="x", padx=300, pady=20)
- self.signUp.pack(side="top", fill="x", padx=300, pady=5)
- self.selectButton.pack(side="top", pady=20)
- self.logoutButton.pack(side="bottom", pady=10)
- self.changePasswordButton.pack(side="bottom")
- # Displays the user's details, their username, current score and the date they last were on the program
- def showScore():
- if window.activeUser != "" and window.activeUser != "Admin":
- score = USERNAMES[window.activeUser][1]
- messagebox.showinfo("Your Details","Username : {0}\n\nScore : {1}".format(window.activeUser,score), icon="info")
- else:
- messagebox.showinfo("Error","Cannot display score\n\nYou are not logged in as a student", icon="warning")
- def changePassword():
- if window.activeUser != "" and window.activeUser != "Admin": # Don't switch to changePasswordPage if noone is logged off, or the admin is logged in
- controller.show_frame(changePasswordPage)
- else:
- messagebox.showinfo("Error","Please login before trying to change your password", icon="warning")
- self.login.focus()
- class changePasswordPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Change Password", font=LARGEFONT)
- self.title.pack(padx=10, pady=10)
- self.originalPasswordText = tk.Label(self, text = "Original Password:")
- self.originalPasswordInput = tk.Entry(self, justify="center", show="*", width=30)
- self.newPasswordText = tk.Label(self, text = "New Password:")
- self.newPasswordInput = tk.Entry(self, justify="center", show="*", width=30)
- self.confirmPasswordText = tk.Label(self, text = "Confirm Password:")
- self.confirmPasswordInput = tk.Entry(self, justify="center", show="*", width=30)
- self.changePasswordButton = tk.Button(self,text = "Change Password", command=lambda: changePassword())
- self.originalPasswordText.pack(side="top", fill="x", padx=20, pady=5)
- self.originalPasswordInput.pack(side="top")
- self.originalPasswordInput.focus()
- self.newPasswordText.pack(side="top", fill="x", padx=20, pady=5)
- self.newPasswordInput.pack(side="top")
- self.confirmPasswordText.pack(side="top", fill="x", padx=20, pady=5)
- self.confirmPasswordInput.pack(side="top")
- self.changePasswordButton.pack(side="top", fill="y", padx=20, pady=10)
- def changePassword():
- if self.originalPasswordInput.get() == USERNAMES[window.activeUser][0]:
- if self.newPasswordInput.get() == self.confirmPasswordInput.get():
- USERNAMES[window.activeUser][0] = self.newPasswordInput.get()
- messagebox.showinfo("Password Changed","Your password has been changed successfully!", icon="info")
- controller.show_frame(accountPage)
- else:
- messagebox.showinfo("Error","Your new and confirmation password do not match\nPlease try again", icon="warning")
- self.newPasswordInput.delete(0,"end")
- self.confirmPasswordInput.delete(0,"end")
- self.newPasswordInput.focus()
- else:
- messagebox.showinfo("Error","Incorrect original password\nPlease try again", icon="warning")
- self.originalPasswordInput.delete(0,"end")
- self.newPasswordInput.delete(0,"end")
- self.confirmPasswordInput.delete(0,"end")
- self.newPasswordInput.focus()
- class loginPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Login", font=LARGEFONT)
- self.title.pack(side="top", fill="x", pady=30)
- # User details entry boxes
- self.usernameText = tk.Label(self, text = "Username:")
- self.usernameInput = tk.Entry(self, justify="center", width=30)
- self.passwordText = tk.Label(self, text = "Password:")
- self.passwordInput = tk.Entry(self, show="*", justify="center", width=30)
- self.loginButton = tk.Button(self,text = "Login", command=lambda: login())
- self.usernameText.pack(side="top", fill="x", padx=20, pady=5)
- self.usernameInput.pack(side="top", pady=5)
- self.usernameInput.focus()
- self.passwordText.pack(side="top", fill="x", padx=20, pady=5)
- self.passwordInput.pack(side="top", pady=5)
- self.loginButton.pack(side="top", pady="10")
- def login(): # Validation ensuring username exists, and that the password given matches the saved password
- if self.usernameInput.get() in USERNAMES: # Checks if the username exists in the database
- if self.passwordInput.get() == USERNAMES[self.usernameInput.get()][0]: # Checks the password matches that of the stored password
- window.activeUser = self.usernameInput.get()
- messagebox.showinfo("Login Successful","Welcome back {0}".format(self.usernameInput.get()), icon = "info")
- self.usernameInput.delete(0,"end") # Deletes value in entry box as it will not be removed automatically when a new frame is raised
- self.passwordInput.delete(0,"end")
- controller.show_frame(homePage)
- window.enableWidgets()
- else:
- self.passwordInput.delete(0,"end")
- messagebox.showinfo("Login Failed", "Incorrect Password", icon = "warning")
- self.passwordInput.focus()
- else:
- self.usernameInput.delete(0,"end")
- self.passwordInput.delete(0,"end")
- 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")
- self.usernameInput.focus()
- class signupPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- title = tk.Label(self, text="Sign Up", font=LARGEFONT)
- title.pack(padx=10, pady=10)
- self.firstNameText = tk.Label(self, text = "First Name:")
- self.firstNameInput = tk.Entry(self, justify="center", width=30)
- self.secondNameText = tk.Label(self, text = "Second Name:")
- self.secondNameInput = tk.Entry(self, justify="center", width=30)
- self.yearOfEntryText = tk.Label(self, text = "Year of Entry to SJP (YYYY):")
- self.yearOfEntryInput = tk.Entry(self, justify="center", width=30)
- self.passwordText = tk.Label(self, text = "New Password:")
- self.passwordInput = tk.Entry(self, show="*", justify="center", width=30)
- self.passwordText2 = tk.Label(self, text = "Confirm Password:")
- self.passwordInput2 = tk.Entry(self, show="*", justify="center", width=30)
- self.signupButton = tk.Button(self,text = "Register", command=lambda: signup())
- # Pack the elements onto the GUI window
- self.firstNameText.pack(side="top", fill="x", padx=20, pady=5)
- self.firstNameInput.pack(side="top")
- self.firstNameInput.focus()
- self.secondNameText.pack(side="top", fill="x", padx=20, pady=5)
- self.secondNameInput.pack(side="top")
- self.yearOfEntryText.pack(side="top", fill="x", padx=20, pady=5)
- self.yearOfEntryInput.pack(side="top")
- self.passwordText.pack(side="top", fill="x", padx=20, pady=5)
- self.passwordInput.pack(side="top")
- self.passwordText2.pack(side="top", fill="x", padx=20, pady=5)
- self.passwordInput2.pack(side="top")
- self.signupButton.pack(side="top", fill="y", padx=20, pady=10)
- def signup():
- # Create local variables that are easier to manipulate inside the function
- firstName = self.firstNameInput.get()
- secondName = self.secondNameInput.get()
- yearOfEntry = self.yearOfEntryInput.get()
- password = self.passwordInput.get()
- if firstName == "" or secondName == "" or yearOfEntry == "" or password == "":
- messagebox.showinfo("Error!","Please do not leave any fields blank", icon = "warning")
- else:
- if yearOfEntry.isdigit() == False or len(yearOfEntry) != 4:
- messagebox.showinfo("Invalid Year of Entry", "Please enter a valid 4 digit year", icon = "warning")
- self.yearOfEntryInput.delete(0,"end")
- self.yearOfEntryInput.focus()
- else:
- if self.passwordInput.get() != self.passwordInput2.get():
- messagebox.showinfo("Passwords do not match", "The passwords you entered did not match\n\nPlease ensure they match", icon = "warning")
- self.passwordInput.delete(0,"end")
- self.passwordInput2.delete(0,"end")
- self.passwordInput.focus()
- else:
- 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
- if newUsername in USERNAMES:
- 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")
- self.firstNameInput.delete(0,"end")
- self.secondNameInput.delete(0,"end")
- self.yearOfEntryInput.delete(0,"end")
- self.passwordInput.delete(0,"end")
- self.passwordInput2.delete(0,"end")
- self.firstNameInput.focus() # Resets the form and focuses the keyboard onto the first entry field
- else:
- 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
- lastSession = [] # This will hold the date which the student last logged out on, it is overwritten when the user logs out of the program
- 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
- window.activeUser = newUsername # Assigns the active user as the newly registered user
- messagebox.showinfo("Registered","Welcome {0}".format(newUsername), icon = "info")
- self.firstNameInput.delete(0,"end")
- self.secondNameInput.delete(0,"end")
- self.yearOfEntryInput.delete(0,"end")
- self.passwordInput.delete(0,"end")
- self.passwordInput2.delete(0,"end")
- window.enableWidgets()
- controller.show_frame(homePage)
- class adminLoginPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Admin Login Page", font=LARGEFONT)
- self.title.pack(side="top", fill="x", pady=30)
- self.usernameText = tk.Label(self, text = "Admin Username:")
- self.usernameInput = tk.Entry(self, justify="center", width=30)
- self.passwordText = tk.Label(self, text = "Admin Password:")
- self.passwordInput = tk.Entry(self, show="*", justify="center", width=30)
- self.loginButton = tk.Button(self,text = "Login", command=lambda: adminLogin())
- self.usernameText.pack(side="top", fill="x", padx=20, pady=5)
- self.usernameInput.pack(side="top", pady=5)
- self.usernameInput.focus()
- self.passwordText.pack(side="top", fill="x", padx=20, pady=5)
- self.passwordInput.pack(side="top", pady=5)
- self.loginButton.pack(side="top", pady="10")
- def adminLogin():
- if self.usernameInput.get() == ADMIN[0]:
- if pbkdf2_sha256.verify(self.passwordInput.get(), ADMIN[1]):
- window.activeUser = self.usernameInput.get()
- messagebox.showinfo("Login Successful","Continue to Admin Page".format(self.usernameInput.get()), icon = "info")
- self.usernameInput.delete(0,"end")
- self.passwordInput.delete(0,"end")
- controller.show_frame(adminPage)
- window.enableWidgets()
- else:
- self.usernameInput.delete(0,"end")
- self.passwordInput.delete(0,"end")
- messagebox.showinfo("Login Failed", "Incorrect details", icon = "warning")
- self.usernameInput.focus()
- else:
- self.usernameInput.delete(0,"end")
- self.passwordInput.delete(0,"end")
- messagebox.showinfo("Login Failed", "Incorrect details", icon = "warning")
- self.usernameInput.focus()
- class adminPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Admin Page", font=LARGEFONT)
- self.title.pack(padx=10, pady=10)
- username = StringVar()
- username.set("Usernames")
- self.usernameText = tk.Label(self, text = "Select students to review details:")
- self.usernamesList = list(USERNAMES) # Creates an array, holding all the key values from the dictionary USERNAMES
- if self.usernamesList == []:
- self.usernamesList.append("No active users")
- self.dropdown = OptionMenu(self, username, *self.usernamesList)
- self.updateButton = tk.Button(self,text = "Update and Sort (Alphabetically)", command=lambda: updateUsernames())
- self.selectButton = tk.Button(self,text = "Search", command=lambda: searchUsername())
- self.usernameText.pack(side="top", padx=20, pady=5)
- self.dropdown.pack(side="top", padx=20, pady=5)
- self.updateButton.pack(side="top", pady=10)
- self.selectButton.pack(side="top")
- # Displays the user's details, their username, current score and the date they last were on the program
- def searchUsername():
- if username.get() in USERNAMES:
- score = USERNAMES[username.get()][1]
- lastSession = USERNAMES[username.get()][2]
- 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]))
- username.set("Usernames")
- # Updates the usernames list, sorting them into alphabetical order of their username, allowing the teacher to easily search for a student
- def updateUsernames():
- username.set("Usernames")
- self.dropdown["menu"].delete(0,"end")
- self.usernamesList = list(USERNAMES) # Takes into account any new users
- self.usernamesList = mergeSort(self.usernamesList) # Calls global function to merge sort the list of
- for each in self.usernamesList:
- self.dropdown["menu"].add_command(label=each, command=tk._setit(username, each))
- class homePage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Learning Options Page", font=LARGEFONT)
- self.title.pack(padx=10, pady=10)
- self.welcomeMsg = tk.Label(self, text = "Welcome to the Physics Learning Aid!")
- self.forcesButton = tk.Button(self, text = "1. Forces", command=lambda: controller.show_frame(forcesPage),height=2,width=20)
- self.label1 = tk.Label(self, text = "or ")
- self.timeGraphsButton = tk.Button(self, text = "2. Time Graphs", command=lambda: controller.show_frame(timeGraphsPage),height=2,width=20)
- self.label2 = tk.Label(self, text = "or ")
- self.SUVATRevisionButton = tk.Button(self, text = "3. SUVAT Revision", command=lambda: controller.show_frame(SUVATRevisionPage),height=2,width=20)
- self.welcomeMsg.pack(side="top", fill="x", padx=5, pady=20)
- self.forcesButton.pack(side="top", pady=5)
- self.label1.pack(side="top", fill="x", pady=5)
- self.timeGraphsButton.pack(side="top", pady=5)
- self.label2.pack(side="top", fill="x", pady=5)
- self.SUVATRevisionButton.pack(side="top", pady=5)
- # Forces Pages #
- class forcesPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Forces Page", font=LARGEFONT)
- self.title.pack(padx=10, pady=10)
- self.label = tk.Label(self, text = "Forces Topics:", font = MEDIUMFONT)
- self.ScalarsVectorsButton = tk.Button(self, text = "Scalars and Vectors", command=lambda: controller.show_frame(ScalarsVectorsPage))
- self.AdditionVectorsCalculationButton = tk.Button(self, text = "Addition of Vectors - Calculation", command=lambda: controller.show_frame(AdditionVectorsCalculationPage))
- self.AdditionVectorsScaleDrawingButton = tk.Button(self, text = "Addition of Vectors - Scale Drawing", command=lambda: controller.show_frame(AdditionVectorsScaleDrawingPage))
- self.ResolutionOfVectorsButton = tk.Button(self, text = "Resolution of Vectors", command=lambda: controller.show_frame(ResolutionOfVectorsPage))
- self.VectorsInEquilibriumButton = tk.Button(self, text = "Vectors in Equilibrium", command=lambda: controller.show_frame(VectorsInEquilibriumPage))
- self.InclinedPlaneVectorsButton = tk.Button(self, text = "Inclined Plane Vectors", command=lambda: controller.show_frame(InclinedPlaneVectorsPage))
- self.label.pack(side="top", fill="x", pady=10)
- self.ScalarsVectorsButton.pack(side="top", pady=15, ipadx=10)
- self.AdditionVectorsCalculationButton.pack(side="top", pady=15, ipadx=10)
- self.AdditionVectorsScaleDrawingButton.pack(side="top", pady=15, ipadx=10)
- self.ResolutionOfVectorsButton.pack(side="top", pady=15, ipadx=10)
- self.VectorsInEquilibriumButton.pack(side="top", pady=15, ipadx=10)
- self.InclinedPlaneVectorsButton.pack(side="top", pady=15, ipadx=10)
- class ScalarsVectorsPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Scalars and Vectors Page", font=LARGEFONT)
- self.title.pack(padx=10, pady=10)
- self.canvas = Canvas(self, width=800, height=500, bd=2)
- self.canvas.pack()
- self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnForces())
- self.returnButton.pack(ipadx=10)
- self.canvas.create_line(400, 0, 400, 350)
- self.canvas.create_line(400, 400, 400, 500)
- self.canvas.create_line(20, 375, 325, 375)
- self.canvas.create_line(475, 375, 780, 375)
- self.canvas.create_text(200, 15, text = "Scalars", font = MEDIUMFONT)
- self.canvas.create_line(100, 175, 300, 75, arrow=BOTH, arrowshape="2 1 10")
- self.canvas.create_text(160, 100, text = "2 metres", font = LABELFONT)
- self.canvas.create_text(200, 250, text = "Scalars have size / length / magnitude", font = LABELFONT)
- self.canvas.create_text(200, 300, text = "They have no direction", font = MEDIUMFONT)
- self.canvas.create_text(600, 15, text = "Vectors", font = MEDIUMFONT)
- self.canvas.create_text(500, 60, text = "North", font = LABELFONT)
- self.canvas.create_line(500, 175, 500, 75, arrow=LAST) # North arrow
- self.canvas.create_line(500, 175, 700, 75, arrow=LAST) # Scalar arrow
- self.canvas.create_arc(475, 150, 525, 200, start = 90.0, extent = -63.44)
- self.canvas.create_text(660, 135, text = "2 metres", font = LABELFONT)
- self.canvas.create_text(520, 140, text = "Θ", font = LABELFONT)
- self.canvas.create_text(600, 250, text = "Vectors have size / length / magnitude", font = LABELFONT)
- self.canvas.create_text(600, 300, text = "They also have a direction / bearing", font = LABELFONT)
- self.canvas.create_text(400, 375, text = "Examples", font = MEDIUMFONT)
- self.canvas.create_text(120, 435, text = "Speed", font = MEDIUMFONT)
- self.canvas.create_text(200, 470, text = "Mass", font = MEDIUMFONT)
- self.canvas.create_text(280, 435, text = "Distance", font = MEDIUMFONT)
- self.canvas.create_text(465, 435, text = "Velocity", font = MEDIUMFONT)
- self.canvas.create_text(515, 470, text = "Force", font = MEDIUMFONT)
- self.canvas.create_text(565, 435, text = "Weight", font = MEDIUMFONT)
- self.canvas.create_text(650, 470, text = "Acceleration", font = MEDIUMFONT)
- self.canvas.create_text(700, 435, text = "Displacement", font = MEDIUMFONT)
- def returnForces():
- window.addScore(2)
- messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
- controller.show_frame(forcesPage)
- class AdditionVectorsCalculationPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Addition of Vectors - Calculation Page", font=LARGEFONT)
- self.title.pack(padx=10, pady=10)
- self.canvas = Canvas(self, width=800, height=500, bd=2)
- self.canvas.pack()
- self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnForces())
- self.returnButton.pack(ipadx=10)
- self.canvas.create_line(25, 150, 425, 20, arrow=LAST, arrowshape="16 20 6")
- self.canvas.create_rectangle(400, 125, 425, 150)
- self.canvas.create_arc(-50, 100, 100, 200, extent = 25.5)
- self.canvas.create_text(110, 135, text = "Θ", font = LABELFONT)
- self.canvas.create_line(425, 150, 425,50, arrow=LAST, arrowshape="12 16 4", fill="red")
- self.canvas.create_line(425, 50, 425, 20, fill="red")
- self.canvas.create_line(25, 150, 375, 150, arrow=LAST, arrowshape="12 16 4", fill="blue")
- self.canvas.create_line(375, 150, 425, 150, fill="blue")
- self.canvas.create_text(450, 75, text = "a", font = LABELFONT, fill="red")
- self.canvas.create_text(225, 170, text = "b", font = LABELFONT, fill="blue")
- self.canvas.create_text(225, 50, text = "c", font = LABELFONT)
- self.canvas.create_text(625, 75, text = """You will only ever be asked
- to add vectors by calculation
- with vectors at right angles
- Therefore, addition of vectors
- by calculation simply requires
- Pythagoras's Theorem""", font = LABELFONT)
- self.canvas.create_text(175, 225, text = "PYTHAGORAS", font = LARGEFONT)
- self.canvas.create_text(175, 275, text = "a^2 + b^2 = c^2", font = LARGEFONT)
- self.canvas.create_text(175, 375, text = "TRIGONOMETRY", font = LARGEFONT)
- self.canvas.create_text(175, 425, text = "tan Θ = a / b", font = LARGEFONT)
- self.canvas.create_text(550, 325, text = """You may be asked to find the final vector
- after travelling along two vectors
- In which case, substitute in 'a' and 'b'
- and rearrange to find 'c'
- which will be your vector's magnitude
- Use trigonometry to find
- the angle of the vector""", font = LABELFONT)
- def returnForces():
- window.addScore(2)
- messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
- controller.show_frame(forcesPage)
- class AdditionVectorsScaleDrawingPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Addition of Vectors - Scale Drawing Page", font=LARGEFONT)
- self.title.pack(padx=10, pady=10)
- self.canvas = Canvas(self, width=800, height=500, bd=2)
- self.canvas.pack()
- self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnForces())
- self.returnButton.pack(ipadx=10)
- self.canvas.create_text(50, 10, text = "North", font = LABELFONT)
- self.canvas.create_line(50, 200, 50, 20, dash=True, arrow=LAST, arrowshape="12 16 4") # North Arrow
- self.canvas.create_arc(25, 175, 75, 225, start = 90.0, extent = -45.0)
- self.canvas.create_text(175, 10, text = "North", font = LABELFONT)
- self.canvas.create_line(175, 75, 175, 20, dash=True, arrow=LAST, arrowshape="12 16 4") # North Arrow
- self.canvas.create_rectangle(175, 75, 190, 60)
- self.canvas.create_line(50, 200, 175, 75, arrow=LAST, arrowshape="16 20 6", fill="red")
- self.canvas.create_line(175, 75, 425, 75, arrow=LAST, arrowshape="16 20 6", fill="blue")
- self.canvas.create_text(160, 155, text = "10 KM\nVector a", font = LABELFONT, fill="red")
- self.canvas.create_text(300, 100, text = "20 KM\nVector b", font = LABELFONT, fill="blue")
- self.canvas.create_text(75, 145, text = "45°", font = LABELFONT)
- self.canvas.create_text(620, 125, text = """You can be asked to add two vectors
- by scale drawing
- The angle between these vectors is
- NOT limited to right angles
- You must draw the vectors
- to scale""", font = LABELFONT)
- self.canvas.create_text(400, 240, text = "DRAW TO SCALE - DECLARE YOUR SCALE", font = LARGEFONT)
- self.canvas.create_rectangle(15, 285, 145, 315)
- self.canvas.create_text(80, 300, text = "1 KM = 1 CM", font = LABELFONT)
- self.canvas.create_text(50, 340, text = "North", font = LABELFONT)
- self.canvas.create_line(50, 460, 50, 350, dash=True, arrow=LAST, arrowshape="12 16 4") # North Arrow
- self.canvas.create_arc(25, 435, 75, 485, start = 90.0, extent = -72.5)
- self.canvas.create_text(65, 425, text = "Θ", font = LABELFONT)
- self.canvas.create_line(50, 460, 175, 335, arrow=LAST, arrowshape="16 20 6", fill="red")
- self.canvas.create_line(175, 335, 425, 335, arrow=LAST, arrowshape="16 20 6", fill="blue")
- self.canvas.create_text(120, 370, text = "a", font = LABELFONT, fill="red")
- self.canvas.create_text(280, 320, text = "b", font = LABELFONT, fill="blue")
- self.canvas.create_text(150, 400, text = "10 CM", font = LABELFONT, fill="red")
- self.canvas.create_text(280, 355, text = "20 CM", font = LABELFONT, fill="blue")
- self.canvas.create_line(50, 460, 425, 335, fill="red")
- self.canvas.create_line(50, 460, 425, 335, dash=True, fill="blue")
- self.canvas.create_text(300, 420, text = "Resultant Vector", font = MEDIUMFONT, fill="red")
- 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)
- def returnForces():
- window.addScore(2)
- messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
- controller.show_frame(forcesPage)
- class ResolutionOfVectorsPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Resolution of Vectors Page", font=LARGEFONT)
- self.title.pack(padx=10, pady=10)
- self.canvas = Canvas(self, width=800, height=500, bd=2)
- self.canvas.pack()
- self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnForces())
- self.returnButton.pack(ipadx=10)
- self.canvas.create_line(50, 150, 450, 20, arrow=LAST, arrowshape="16 20 6")
- self.canvas.create_line(50, 150, 50, 20, dash=True, arrow=LAST, arrowshape="12 16 4", fill="red")
- self.canvas.create_line(50, 150, 450, 150, dash=True, arrow=LAST, arrowshape="12 16 4", fill="blue")
- self.canvas.create_text(250, 50, text = "? ms^-1", font = LABELFONT)
- self.canvas.create_text(100, 75, text = "3 ms^-1", font = LABELFONT, fill="red")
- self.canvas.create_text(250, 175, text = "4 ms^-1", font = LABELFONT, fill="blue")
- self.canvas.create_text(625, 100, text = """Similar to addition of vectors
- by calculation
- Every vector has a vertical
- and horizontal component
- Simply add the two components
- in order to find the vector's
- magnitude""", font = LABELFONT)
- self.canvas.create_line(350, 390, 750, 240, arrow=LAST, arrowshape="16 20 6")
- self.canvas.create_rectangle(725, 365, 750, 390)
- self.canvas.create_arc(300, 340, 400, 440, extent = 20.5)
- self.canvas.create_text(420, 377, text = "Θ", font = LABELFONT)
- self.canvas.create_line(750, 390, 750, 290, arrow=LAST, arrowshape="12 16 4", fill="red")
- self.canvas.create_line(750, 290, 750, 240, fill="red")
- self.canvas.create_line(350, 390, 700, 390, arrow=LAST, arrowshape="12 16 4", fill="blue")
- self.canvas.create_line(700, 390, 750, 390, fill="blue")
- self.canvas.create_text(775, 315, text = "a", font = LABELFONT, fill="red")
- self.canvas.create_text(550, 410, text = "b", font = LABELFONT, fill="blue")
- self.canvas.create_text(550, 290, text = "c", font = LABELFONT)
- self.canvas.create_text(100, 245, text = "a^2 + b^2 = c^2", font = LABELFONT)
- self.canvas.create_text(100, 295, text = "3^2 + 4^2 = c^2", font = LABELFONT)
- self.canvas.create_text(100, 345, text = "c^2 = 25", font = LABELFONT)
- self.canvas.create_text(100, 395, text = "c = 5", font = LABELFONT)
- self.canvas.create_text(310, 245, text = "arg Θ = 3 / 4", font = LABELFONT)
- self.canvas.create_text(310, 295, text = "Θ = tan^-1( 0.75 )", font = LABELFONT)
- self.canvas.create_text(310, 345, text = "Θ ≈ 53°", font = LABELFONT)
- self.canvas.create_text(475, 465, text = "Vector Magnitude is 5 ms^-1, Vector Angle is 53°", font = LABELFONT)
- def returnForces():
- window.addScore(2)
- messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
- controller.show_frame(forcesPage)
- class VectorsInEquilibriumPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Vectors In Equilibrium Page", font=LARGEFONT)
- self.title.pack(padx=10, pady=10)
- self.canvas = Canvas(self, width=800, height=500, bd=2)
- self.canvas.pack()
- self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnForces())
- self.returnButton.pack(ipadx=10)
- self.canvas.create_text(400, 20, text = "F = ma", font = LARGEFONT)
- self.canvas.create_text(400, 50, text = "When an object is in equilibrium, the resultant force acting on it is 0", font = LABELFONT)
- self.canvas.create_text(400, 70, text = "If F = 0, ma = 0. Assuming the object has mass, when in equilibrium, acceleration = 0", font = LABELFONT)
- self.canvas.create_text(400, 90, text = "When acceleration = 0, the object has constant velocity", font = LABELFONT)
- # Underline
- self.canvas.create_line(160, 102, 640, 102)
- # Page divider
- self.canvas.create_line(400, 110, 400, 490)
- # At rest
- self.canvas.create_text(200, 135, text = "Objects in equilibrium - at rest", font = MEDIUMFONT)
- self.canvas.create_line(20, 260, 380, 260)
- self.canvas.create_rectangle(175, 210, 225, 260)
- self.canvas.create_oval(198, 233, 202, 237, fill="black")
- self.canvas.create_text(50, 250, text = "Table", font = SMALLFONT)
- self.canvas.create_line(200, 160, 200, 235, fill="blue", arrow=FIRST)
- self.canvas.create_text(280, 185, text = "Reaction Force", font = LABELFONT, fill="blue")
- self.canvas.create_line(200, 235, 200, 310, fill="red", arrow=LAST)
- self.canvas.create_text(165, 285, text = "Weight ", font = LABELFONT, fill="red")
- self.canvas.create_text(200, 350, text = "The table supports the block by exerting a", font = LABELFONT)
- self.canvas.create_text(200, 390, text = "reaction force equal to the blocks weight", font = LABELFONT)
- self.canvas.create_text(200, 430, text = "Resultant force is 0 and so its acceleration", font = LABELFONT)
- self.canvas.create_text(200, 470, text = "is 0. Therefore it stays at rest", font = LABELFONT)
- # Moving
- self.canvas.create_text(600, 135, text = "Objects in equilibrium - moving", font = MEDIUMFONT)
- self.canvas.create_text(600, 180, text = "Velocity = 30 ms^-1", font = LABELFONT)
- self.canvas.create_line(420, 290, 780, 290)
- try:
- self.Car = tk.PhotoImage(file = "NEACar.png")
- self.canvas.create_image(600, 260, image=self.Car)
- except:
- self.canvas.create_text(600, 260, text = "Car Image not found")
- self.canvas.create_line(537, 260, 450, 260, fill="red", arrow=LAST)
- self.canvas.create_text(490, 240, text = "Thrust ", font = LABELFONT, fill="red")
- self.canvas.create_line(663, 260, 750, 260, fill="blue", arrow=LAST)
- self.canvas.create_text(710, 230, text = "Air Resistance", font = LABELFONT, fill="blue")
- self.canvas.create_line(635, 290, 750, 290, fill="blue", arrow=LAST)
- self.canvas.create_text(690, 305, text = "Friction", font = LABELFONT, fill="blue")
- self.canvas.create_text(600, 345, text = "If in equilibrium,", font = LABELFONT)
- self.canvas.create_text(600, 375, text = "Thrust = Air Resistance + Friction,", font = LABELFONT)
- self.canvas.create_text(600, 405, text = "so the overall force on the car is 0", font = LABELFONT)
- self.canvas.create_text(600, 435, text = "So its acceleration is 0", font = LABELFONT)
- self.canvas.create_text(600, 465, text = "Therefore it stays at its current velocity", font = LABELFONT)
- def returnForces():
- window.addScore(2)
- messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
- controller.show_frame(forcesPage)
- class InclinedPlaneVectorsPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Inclined Plane Vectors Page", font=LARGEFONT)
- self.title.pack(padx=10, pady=10)
- self.canvas = Canvas(self, width=800, height=500, bd=2)
- self.canvas.pack()
- self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnForces())
- self.returnButton.pack(ipadx=10)
- self.canvas.create_text(400, 25, text = "When an object is stationary on an inclined plane, 3 forces are acting on it", font = MEDIUMFONT)
- self.canvas.create_text(400, 50, text = "1. Weight of the object, acting vertically downwards", font = SMALLFONT)
- self.canvas.create_text(400, 75, text = "2. The Support / Reaction force, acting perpendicular to where the weight acts on the plane", font = SMALLFONT)
- self.canvas.create_text(400, 100, text = "3. Friction, acting parallel to the plane", font = SMALLFONT)
- # Box
- self.canvas.create_polygon(120, 225, 160, 215, 150, 175, 110, 185, fill="white", outline="black")
- self.canvas.create_oval(133, 198, 137, 202, fill="black")
- # Weight arrow
- self.canvas.create_line(135, 125, 135, 220, fill="green", arrow=LAST)
- self.canvas.create_text(160, 150, text = "Weight", fill="green")
- # Support Arrow
- self.canvas.create_line(135, 220, 90, 135, fill="blue", arrow=LAST)
- self.canvas.create_text(70, 160, text = "Support", fill="blue")
- # Friction Arrows
- self.canvas.create_line(90, 135, 135, 125, fill="red", arrow=LAST)
- self.canvas.create_text(105, 115, text = "Friction", fill="red")
- self.canvas.create_line(135, 220, 175, 210, fill="red", arrow=LAST)
- # Triangle
- self.canvas.create_arc(-40, 190, 80, 310, extent = 14.0)
- self.canvas.create_line(20, 250, 500, 250, fill="green")
- self.canvas.create_line(500, 250, 420, 150, fill="red")
- self.canvas.create_line(20, 250, 420, 150, fill="blue")
- self.canvas.create_text(100, 240, text = "Θ", font = SMALLFONT)
- 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)
- # New Triangle
- self.canvas.create_arc(210, 390, 330, 510, extent = 14.0)
- self.canvas.create_line(270, 450, 750, 450, fill="green", arrow=FIRST)
- self.canvas.create_line(750, 450, 670, 350, fill="red", arrow=FIRST)
- self.canvas.create_line(270, 450, 670, 350, fill="blue", arrow=LAST)
- self.canvas.create_text(350, 440, text = "Θ", font = SMALLFONT)
- self.canvas.create_text(550, 465, text = "Weight", fill="green")
- self.canvas.create_text(470, 380, text = "Support", fill="blue")
- self.canvas.create_text(740, 390, text = "Friction", fill="red")
- self.canvas.create_text(320, 350, text = """If asked to find out the angle of the inclined plane, use trigonometry
- and your values of weight, support and friction to find Θ
- As the triangle's overall displacement is zero,
- an unknown weight, support or friction force
- will be equal to the negative sum of the
- known values
- e.g. W = -(S + F)""", font = LABELFONT)
- self.canvas.create_text(125, 475, text = "W + S + F = 0", font = MEDIUMFONT)
- def returnForces():
- window.addScore(2)
- messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
- controller.show_frame(forcesPage)
- # Time Graph Pages #
- class timeGraphsPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Time Graphs Page", font=LARGEFONT)
- self.title.pack(padx=10, pady=10)
- self.label = tk.Label(self, text = "Time Graphs:", font = MEDIUMFONT)
- self.GradientsButton = tk.Button(self, text = "Gradients", command=lambda: controller.show_frame(GradientsPage))
- self.AreaUnderCurveButton = tk.Button(self, text = "Area Under Curve", command=lambda: controller.show_frame(AreaUnderCurvePage))
- self.BouncingBallButton = tk.Button(self, text = "Experiment - Bouncing Ball", command=lambda: controller.show_frame(BouncingBallPage))
- self.interactiveGraphsButton = tk.Button(self, text = "Interactive Graphs", command=lambda: controller.show_frame(interactiveGraphsPage))
- self.label.pack(side="top", fill="x", pady=10)
- self.GradientsButton.pack(side="top", pady=15, ipadx=10)
- self.AreaUnderCurveButton.pack(side="top", pady=15, ipadx=10)
- self.BouncingBallButton.pack(side="top", pady=15, ipadx=10)
- self.interactiveGraphsButton.pack(side="top", pady=15, ipadx=10)
- class GradientsPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Gradients Of Time Graphs Page", font=LARGEFONT)
- self.title.grid(row=0 , column=0, columnspan=2, padx=10, pady=10)
- self.distanceCanvas = Canvas(self, width=400, height=160, bd=2)
- self.distanceCanvas.grid(row=1, column=0)
- self.displacementCanvas = Canvas(self, width=400, height=160, bd=2)
- self.displacementCanvas.grid(row=1, column=1)
- self.speedCanvas = Canvas(self, width=400, height=160, bd=2)
- self.speedCanvas.grid(row=2, column=0)
- self.velocityCanvas = Canvas(self, width=400, height=160, bd=2)
- self.velocityCanvas.grid(row=2, column=1)
- self.accelerationCanvas = Canvas(self, width=400, height=160, bd=2)
- self.accelerationCanvas.grid(row=3, column=0, columnspan=2)
- self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnTimeGraphs())
- self.returnButton.grid(row=4, column=0, ipadx=10)
- self.scalarVectorLabel = tk.Label(self, text = "Blue = Scalar , Red = Vector")
- self.scalarVectorLabel.grid(row=4, column=1, padx=5)
- self.distanceCanvas.create_text(200, 15, text = "Distance - Time Graph",font = MEDIUMFONT, fill="blue")
- self.distanceCanvas.create_line(50, 135, 50, 35, width = 3, fill="blue")
- self.distanceCanvas.create_line(50, 135, 200, 135, width = 3, fill="blue")
- self.distanceCanvas.create_line(50, 135, 195, 40, fill="blue")
- self.distanceCanvas.create_text(25, 85, text = "d",font = LABELFONT, fill="blue")
- self.distanceCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="blue")
- self.distanceCanvas.create_text(300, 55, text = "Gradient",font = LABELFONT, fill="blue")
- self.distanceCanvas.create_text(300, 85, text = "= d / t",font = LABELFONT, fill="blue")
- self.distanceCanvas.create_text(300, 115, text = "= Speed",font = LABELFONT, fill="blue")
- self.displacementCanvas.create_text(200, 15, text = "Displacement - Time Graph",font = MEDIUMFONT, fill="red")
- self.displacementCanvas.create_line(50, 135, 50, 35, width = 3, fill="red")
- self.displacementCanvas.create_line(50, 135, 200, 135, width = 3, fill="red")
- self.displacementCanvas.create_line(50, 135, 195, 40, fill="red")
- self.displacementCanvas.create_text(25, 85, text = "s",font = LABELFONT, fill="red")
- self.displacementCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="red")
- self.displacementCanvas.create_text(300, 55, text = "Gradient",font = LABELFONT, fill="red")
- self.displacementCanvas.create_text(300, 85, text = "= s / t",font = LABELFONT, fill="red")
- self.displacementCanvas.create_text(300, 115, text = "= Velocity",font = LABELFONT, fill="red")
- self.speedCanvas.create_text(200, 15, text = "Speed - Time Graph",font = MEDIUMFONT, fill="blue")
- self.speedCanvas.create_line(50, 135, 50, 35, width = 3, fill="blue")
- self.speedCanvas.create_line(50, 135, 200, 135, width = 3, fill="blue")
- self.speedCanvas.create_line(50, 135, 195, 40, fill="blue")
- self.speedCanvas.create_text(25, 85, text = "s",font = LABELFONT, fill="blue")
- self.speedCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="blue")
- self.speedCanvas.create_text(300, 55, text = "Gradient",font = LABELFONT, fill="blue")
- self.speedCanvas.create_text(300, 85, text = "= s / t",font = LABELFONT, fill="blue")
- self.speedCanvas.create_text(300, 115, text = "Not needed for exam",font = LABELFONT, fill="blue")
- self.velocityCanvas.create_text(200, 15, text = "Velocity - Time Graph",font = MEDIUMFONT, fill="red")
- self.velocityCanvas.create_line(50, 135, 50, 35, width = 3, fill="red")
- self.velocityCanvas.create_line(50, 135, 200, 135, width = 3, fill="red")
- self.velocityCanvas.create_line(50, 135, 195, 40, fill="red")
- self.velocityCanvas.create_text(25, 85, text = "v",font = LABELFONT, fill="red")
- self.velocityCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="red")
- self.velocityCanvas.create_text(300, 55, text = "Gradient",font = LABELFONT, fill="red")
- self.velocityCanvas.create_text(300, 85, text = "= v / t",font = LABELFONT, fill="red")
- self.velocityCanvas.create_text(300, 115, text = "Acceleration",font = LABELFONT, fill="red")
- self.accelerationCanvas.create_text(200, 15, text = "Acceleration - Time Graph",font = MEDIUMFONT, fill="red")
- self.accelerationCanvas.create_line(50, 135, 50, 35, width = 3, fill="red")
- self.accelerationCanvas.create_line(50, 135, 200, 135, width = 3, fill="red")
- self.accelerationCanvas.create_line(50, 135, 195, 40, fill="red")
- self.accelerationCanvas.create_text(25, 85, text = "a",font = LABELFONT, fill="red")
- self.accelerationCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="red")
- self.accelerationCanvas.create_text(300, 55, text = "Gradient",font = LABELFONT, fill="red")
- self.accelerationCanvas.create_text(300, 85, text = "= a / t",font = LABELFONT, fill="red")
- self.accelerationCanvas.create_text(300, 115, text = "Not needed for exam",font = LABELFONT, fill="red")
- def returnTimeGraphs():
- window.addScore(2)
- messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
- controller.show_frame(timeGraphsPage)
- class AreaUnderCurvePage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Area Under Curves Of Time Graphs Page", font=LARGEFONT)
- self.title.grid(row=0, column=0, columnspan=2, padx=10, pady=10)
- self.distanceCanvas = Canvas(self, width=400, height=160, bd=2)
- self.distanceCanvas.grid(row=1, column=0)
- self.displacementCanvas = Canvas(self, width=400, height=160, bd=2)
- self.displacementCanvas.grid(row=1, column=1)
- self.speedCanvas = Canvas(self, width=400, height=160, bd=2)
- self.speedCanvas.grid(row=2, column=0)
- self.velocityCanvas = Canvas(self, width=400, height=160, bd=2)
- self.velocityCanvas.grid(row=2, column=1)
- self.accelerationCanvas = Canvas(self, width=400, height=160, bd=2)
- self.accelerationCanvas.grid(row=3, column=0, columnspan=2)
- self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnTimeGraphs())
- self.returnButton.grid(row=4, column=0, ipadx=10)
- self.scalarVectorLabel = tk.Label(self, text = "Blue = Scalar , Red = Vector")
- self.scalarVectorLabel.grid(row=4, column=1, padx=5)
- self.distanceCanvas.create_text(200, 15, text = "Distance - Time Graph",font = MEDIUMFONT, fill="blue")
- self.distanceCanvas.create_line(50, 135, 50, 35, width = 3, fill="blue")
- self.distanceCanvas.create_line(50, 135, 200, 135, width = 3, fill="blue")
- self.distanceCanvas.create_line(50, 135, 195, 40, fill="blue")
- self.distanceCanvas.create_text(25, 85, text = "d",font = LABELFONT, fill="blue")
- self.distanceCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="blue")
- self.distanceCanvas.create_text(300, 55, text = "Area Under Curve",font = LABELFONT, fill="blue")
- self.distanceCanvas.create_text(300, 85, text = "= d x t",font = LABELFONT, fill="blue")
- self.distanceCanvas.create_text(300, 115, text = "Not needed for exam",font = LABELFONT, fill="blue")
- self.displacementCanvas.create_text(200, 15, text = "Displacement - Time Graph",font = MEDIUMFONT, fill="red")
- self.displacementCanvas.create_line(50, 135, 50, 35, width = 3, fill="red")
- self.displacementCanvas.create_line(50, 135, 200, 135, width = 3, fill="red")
- self.displacementCanvas.create_line(50, 135, 195, 40, fill="red")
- self.displacementCanvas.create_text(25, 85, text = "s",font = LABELFONT, fill="red")
- self.displacementCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="red")
- self.displacementCanvas.create_text(300, 55, text = "Area Under Curve",font = LABELFONT, fill="red")
- self.displacementCanvas.create_text(300, 85, text = "= s x t",font = LABELFONT, fill="red")
- self.displacementCanvas.create_text(300, 115, text = "Not needed for exam",font = LABELFONT, fill="red")
- self.speedCanvas.create_text(200, 15, text = "Speed - Time Graph",font = MEDIUMFONT, fill="blue")
- self.speedCanvas.create_line(50, 135, 50, 35, width = 3, fill="blue")
- self.speedCanvas.create_line(50, 135, 200, 135, width = 3, fill="blue")
- self.speedCanvas.create_line(50, 135, 195, 40, fill="blue")
- self.speedCanvas.create_text(25, 85, text = "s",font = LABELFONT, fill="blue")
- self.speedCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="blue")
- self.speedCanvas.create_text(300, 55, text = "Area Under Curve",font = LABELFONT, fill="blue")
- self.speedCanvas.create_text(300, 85, text = "= s x t",font = LABELFONT, fill="blue")
- self.speedCanvas.create_text(300, 115, text = "= Distance",font = LABELFONT, fill="blue")
- self.velocityCanvas.create_text(200, 15, text = "Velocity - Time Graph",font = MEDIUMFONT, fill="red")
- self.velocityCanvas.create_line(50, 135, 50, 35, width = 3, fill="red")
- self.velocityCanvas.create_line(50, 135, 200, 135, width = 3, fill="red")
- self.velocityCanvas.create_line(50, 135, 195, 40, fill="red")
- self.velocityCanvas.create_text(25, 85, text = "v",font = LABELFONT, fill="red")
- self.velocityCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="red")
- self.velocityCanvas.create_text(300, 55, text = "Area Under Curve",font = LABELFONT, fill="red")
- self.velocityCanvas.create_text(300, 85, text = "= v x t",font = LABELFONT, fill="red")
- self.velocityCanvas.create_text(300, 115, text = "Displacement",font = LABELFONT, fill="red")
- self.accelerationCanvas.create_text(200, 15, text = "Acceleration - Time Graph",font = MEDIUMFONT, fill="red")
- self.accelerationCanvas.create_line(50, 135, 50, 35, width = 3, fill="red")
- self.accelerationCanvas.create_line(50, 135, 200, 135, width = 3, fill="red")
- self.accelerationCanvas.create_line(50, 135, 195, 40, fill="red")
- self.accelerationCanvas.create_text(25, 85, text = "a",font = LABELFONT, fill="red")
- self.accelerationCanvas.create_text(125, 153, text = "t",font = LABELFONT, fill="red")
- self.accelerationCanvas.create_text(300, 55, text = "Area Under Curve",font = LABELFONT, fill="red")
- self.accelerationCanvas.create_text(300, 85, text = "= a x t",font = LABELFONT, fill="red")
- self.accelerationCanvas.create_text(300, 115, text = "Velocity",font = LABELFONT, fill="red")
- def returnTimeGraphs():
- window.addScore(2)
- messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
- controller.show_frame(timeGraphsPage)
- class BouncingBallPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Bouncing Ball Example Page", font=LARGEFONT)
- self.title.grid(row=0, column=0, columnspan=2, padx=10, pady=10)
- self.bouncingBallCanvas = Canvas(self, width=400, height=160, bd=2)
- self.bouncingBallCanvas.grid(row=1, column=0)
- self.distanceCanvas = Canvas(self, width=400, height=160, bd=2)
- self.distanceCanvas.grid(row=1, column=1)
- self.displacementCanvas = Canvas(self, width=400, height=160, bd=2)
- self.displacementCanvas.grid(row=2, column=0)
- self.speedCanvas = Canvas(self, width=400, height=160, bd=2)
- self.speedCanvas.grid(row=2, column=1)
- self.velocityCanvas = Canvas(self, width=400, height=160, bd=2)
- self.velocityCanvas.grid(row=3, column=0)
- self.accelerationCanvas = Canvas(self, width=400, height=160, bd=2)
- self.accelerationCanvas.grid(row=3, column=1)
- self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnTimeGraphs())
- self.returnButton.grid(row=4, column=0, ipadx=10)
- self.scalarVectorLabel = tk.Label(self, text = "Blue = Scalar , Red = Vector")
- self.scalarVectorLabel.grid(row=4, column=1, padx=5)
- self.bouncingBallCanvas.create_oval(50, 10, 90, 50, fill="gray40", outline="gray40")
- self.bouncingBallCanvas.create_oval(50, 150, 90, 110, fill="gray40", outline="gray40")
- self.bouncingBallCanvas.create_line(60, 50, 60, 110, width=2)
- self.bouncingBallCanvas.create_line(80, 50, 80, 110, width=2)
- self.bouncingBallCanvas.create_line(60, 50, 45, 65, width=2)
- self.bouncingBallCanvas.create_line(80, 110, 95, 95, width=2)
- self.bouncingBallCanvas.create_line(20, 152, 130, 152, width = 3)
- self.bouncingBallCanvas.create_text(265, 30, text = "Common Exam Question", font = MEDIUMFONT)
- self.bouncingBallCanvas.create_text(265, 70, text = "Ball projected upward, whilst", font = SMALLFONT)
- self.bouncingBallCanvas.create_text(265, 100, text = "in the air, it is acted on", font = SMALLFONT)
- self.bouncingBallCanvas.create_text(265, 130, text = "by gravity only", font = SMALLFONT)
- self.distanceCanvas.create_text(200, 15, text = "Distance - Time Graph", font = MEDIUMFONT, fill="blue")
- self.distanceCanvas.create_line(125, 135, 125, 35, width = 3, fill="blue")
- self.distanceCanvas.create_line(125, 135, 275, 135, width = 3, fill="blue")
- self.distanceCanvas.create_arc(127, 85, 275, 185, start=90, extent=90, style="arc", outline="blue")
- self.distanceCanvas.create_arc(127, -15, 275, 85, start=-90, extent=90, style="arc", outline="blue")
- self.distanceCanvas.create_text(100, 85, text = "d",font = LABELFONT, fill="blue")
- self.distanceCanvas.create_text(200, 153, text = "t",font = LABELFONT, fill="blue")
- self.displacementCanvas.create_text(200, 15, text = "Displacement - Time Graph",font = MEDIUMFONT, fill="red")
- self.displacementCanvas.create_line(125, 135, 125, 35, width = 3, fill="red")
- self.displacementCanvas.create_line(125, 135, 275, 135, width = 3, fill="red")
- self.displacementCanvas.create_arc(127, 35, 275, 235, extent=180, style="arc", outline="red")
- self.displacementCanvas.create_text(100, 85, text = "s",font = LABELFONT, fill="red")
- self.displacementCanvas.create_text(200, 153, text = "t",font = LABELFONT, fill="red")
- self.speedCanvas.create_text(200, 15, text = "Speed - Time Graph",font = MEDIUMFONT, fill="blue")
- self.speedCanvas.create_line(125, 135, 125, 35, width = 3, fill="blue")
- self.speedCanvas.create_line(125, 135, 275, 135, width = 3, fill="blue")
- self.speedCanvas.create_arc(127, -60, 275, 133, extent=-180, style="arc", outline="blue")
- self.speedCanvas.create_text(100, 85, text = "s",font = LABELFONT, fill="blue")
- self.speedCanvas.create_text(200, 153, text = "t",font = LABELFONT, fill="blue")
- self.velocityCanvas.create_text(200, 15, text = "Velocity - Time Graph",font = MEDIUMFONT, fill="red")
- self.velocityCanvas.create_line(125, 135, 125, 35, width = 3, fill="red")
- self.velocityCanvas.create_line(125, 85, 275, 85, width = 3, fill="red")
- self.velocityCanvas.create_line(125, 35, 275, 135, fill="red")
- self.velocityCanvas.create_text(100, 85, text = "v",font = LABELFONT, fill="red")
- self.velocityCanvas.create_text(295, 85, text = "t",font = LABELFONT, fill="red")
- self.accelerationCanvas.create_text(200, 15, text = "Acceleration - Time Graph",font = MEDIUMFONT, fill="red")
- self.accelerationCanvas.create_line(125, 135, 125, 35, width = 3, fill="red")
- self.accelerationCanvas.create_line(125, 85, 275, 85, width = 3, fill="red")
- self.accelerationCanvas.create_line(125, 50, 275, 50, fill="red")
- self.accelerationCanvas.create_text(100, 85, text = "a",font = LABELFONT, fill="red")
- self.accelerationCanvas.create_text(295, 85, text = "t",font = LABELFONT, fill="red")
- self.accelerationCanvas.create_text(329, 49, text = "= 9.8 ms^-1",font = SMALLFONT, fill="red")
- def returnTimeGraphs():
- window.addScore(2)
- messagebox.showinfo("Score Updated","You earned 2 points for visiting this page", icon = "info")
- controller.show_frame(timeGraphsPage)
- class interactiveGraphsPage(tk.Frame):
- def __init__(self, parent, controller):
- self.interactiveGraphsPage = True
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="Interactive Graphs Page", font=LARGEFONT)
- self.title.pack(side="top", padx=10, pady=10)
- # Draws the backend graph onto the tkinter page
- canvas = FigureCanvasTkAgg(f, self)
- canvas.show()
- canvas.get_tk_widget().pack(side="top")
- # Draws the matplotlib's navigation tool onto the canvas
- toolbar = NavigationToolbar2TkAgg(canvas, self)
- toolbar.update()
- canvas._tkcanvas.pack(side="top")
- # Creates the graph controller window
- self.graphControllerDisplayButton = tk.Button(self, text = "Click for Graph Controller", command=lambda: self.createGraphController())
- self.graphControllerDisplayButton.pack(side="left", ipadx=10, padx=80, pady=1)
- self.returnButton = tk.Button(self, text = "Return - Click to earn points for visiting this revision page", command=lambda: returnTimeGraphs())
- self.returnButton.pack(side="left", ipadx=10, padx=61, pady=1)
- def returnTimeGraphs():
- window.addScore(5)
- messagebox.showinfo("Score Updated","You earned 5 points for visiting this page", icon = "info")
- controller.show_frame(timeGraphsPage)
- def onclick(event): # Called when graph canvas is clicked
- try: # If user clicks outside of the graph, it causes an error. If not, call the onClickFunction
- onclickFunction(event)
- except: # If they do click outside the graph, nothing should happen so just pass
- pass
- def onclickFunction(event): # Called when graph is clicked
- xValue = event.xdata # Retrieves the x coordinate of the user's click
- if xValue % 1 != 0: # Checks whether x coordinate has a gradient, if yes....
- yValue = event.ydata # Retrieves the y coordinate of the user's click
- lowerX = math.floor(xValue) #
- upperX = math.ceil(xValue)
- try:
- lowerPosition = animationState.xList.index(lowerX)
- lowerY = animationState.yList[lowerPosition]
- upperPosition = animationState.xList.index(upperX)
- upperY = animationState.yList[upperPosition]
- gradient = (upperY - lowerY)/(upperX - lowerX)
- units = animationState.gradientUnits()
- messagebox.showinfo("Gradient", "Gradient = {0} {1}".format(gradient, units), icon="info")
- except:
- messagebox.showinfo("Error", "Not enough data\n\nClick somewhere where a line is present", icon="warning")
- else: # Called if user clicks where x coordinate is an integer
- messagebox.showinfo("Error", "You have clicked where the line changes gradient\n\nTry again", icon="warning")
- f.canvas.callbacks.connect("button_press_event", onclick) # When the user clicks on the graph canvas, call the onlick function
- def createGraphController(self): # Creates the graph controller window, if its already made, focus on the window
- try:
- self.graphController.lift()
- self.graphController.focus_force()
- except:
- self.graphController = GraphController()
- self.graphController.protocol("WM_DELETE_WINDOW", self.closeGraphController)
- self.graphController.mainloop()
- def closeGraphController(self): # Pauses the backend of the graph, and destroys the graph controller window
- animationState.play = False
- self.graphController.destroy()
- class GraphController(tk.Tk):
- def __init__(self, *args, **kwargs):
- self.present = True
- tk.Tk.__init__(self, *args, **kwargs)
- tk.Tk.iconbitmap(self, default="NEALogo.ico")
- tk.Tk.wm_title(self, "Graph Controller")
- self.geometry("480x350")
- self.resizable(width=False,height=False)
- self.currentState = tk.Label(self, text = "Graph is: Paused")
- self.currentState.grid(row=0, column=0, padx=30, pady=20)
- self.playPauseButton = tk.Button(self, text="Play/Pause", command=lambda: self.playPause())
- self.playPauseButton.grid(row=0, column=1, padx=30, pady=20)
- self.line1 = tk.Label(self, text = "---------------------------------------------------------")
- self.line1.grid(row=1, column=0, columnspan=2)
- self.selectGraphType = tk.Label(self, text = "Select Graph Type: (Default is Distance-Time Graph)")
- self.selectGraphType.grid(row=2, column=0, columnspan=2, padx=30, pady=15)
- self.distanceButton = tk.Button(self, text = "Distance-Time Graph", command=lambda: self.changeLabels("distance /m"))
- self.distanceButton.grid(row=3, column=0, padx=10, pady=10)
- self.displacementButton = tk.Button(self, text = "Displacement-Time Graph", command=lambda: self.changeLabels("displacement /m"))
- self.displacementButton.grid(row=3, column=1, padx=10, pady=10)
- self.speedButton = tk.Button(self, text = "Speed-Time Graph", command=lambda: self.changeLabels("speed /ms^-1"))
- self.speedButton.grid(row=4, column=0, padx=10, pady=10)
- self.velocityButton = tk.Button(self, text = "Velocity-Time Graph", command=lambda: self.changeLabels("velocity /ms^-1"))
- self.velocityButton.grid(row=4, column=1, padx=10, pady=10)
- self.accelerationButton = tk.Button(self, text = "Acceleration-Time Graph", command=lambda: self.changeLabels("acceleration /ms^-2"))
- self.accelerationButton.grid(row=5, column=0, columnspan=2, padx=10, pady=10)
- self.line2 = tk.Label(self, text = "---------------------------------------------------------")
- self.line2.grid(row=6, column=0, columnspan=2)
- self.areaUnderGraphButton = tk.Button(self, text = "Area Under Graph", command=lambda: self.areaUnderGraph())
- self.areaUnderGraphButton.grid(row=7, column=0, padx=10, pady=10)
- self.clearGraphButton = tk.Button(self, text = "Clear Graph", command=lambda: self.clearGraph())
- self.clearGraphButton.grid(row=7, column=1, padx=10, pady=10)
- self.line3 = tk.Label(self, text = """|
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |""")
- self.line3.grid(row=0, column=2, rowspan=8, padx=5)
- self.gradientLabel = tk.Label(self, text = "Slide to change\ngraph gradient")
- self.gradientLabel.grid(row=0, column=3, sticky=N, padx=13, pady=15)
- self.gradientScale = tk.Scale(self, from_=10, to=-10, length=250)
- self.gradientScale.grid(row=1, column=3, rowspan=7, sticky=W, padx=25)
- self.scaleLabel = tk.Label(self, text = "- 0")
- self.scaleLabel.place(x=423, y=193)
- def playPause(self): # Pauses or runs the backend of the graph
- animationState.changeState()
- if animationState.play == True:
- self.currentState.configure(text="Graph is: Running") # Changes the label on the graph controller as well
- elif animationState.play == False:
- self.currentState.configure(text="Graph is: Paused")
- def changeLabels(self, graphType): # Alters the graph's axis labels to the appropriate graph
- self.clearGraph()
- titlePart = graphType.capitalize()
- titlePart2 = titlePart.split(" ")[0]
- title = "{0}-Time Graph".format(titlePart2)
- animationState.title = title
- animationState.ylabel = graphType
- animationState.xlabel = "time /s"
- def changeGradient(self, changeAmount):
- animationState.currentGradient += changeAmount
- def areaUnderGraph(self):
- area = areaUnderCurve(animationState.xList, animationState.yList)
- if area == "N/A": # Returned from areaUnderCurve function, means not enough data was given
- pass
- else:
- units = animationState.areaUnits()
- messagebox.showinfo("Area Under Curve", "Area Under Curve = {0} {1}".format(area, units), icon="info")
- def clearGraph(self): # Clears the graph, resets the lists of coordinates and resets the xCounter
- a.clear()
- animationState.xList = [0]
- animationState.yList = [0]
- animationState.xCounter = 1
- # SUVAT Revision Pages #
- class SUVATRevisionPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="SUVAT Revision Page", font=LARGEFONT)
- self.title.pack(side="top", fill="x", pady=30)
- self.SUVATCheckerButton = tk.Button(self, text = "SUVAT Checker", command=lambda: controller.show_frame(SUVATCheckerPage),height=2,width=20)
- self.label1 = tk.Label(self, text = "or ")
- self.SUVATSolverButton = tk.Button(self, text = "SUVAT Solver", command=lambda: controller.show_frame(SUVATSolverPage),height=2,width=20)
- self.SUVATCheckerButton.pack(side="top", pady=5)
- self.label1.pack(side="top", fill="x", pady=5)
- self.SUVATSolverButton.pack(side="top", pady=5)
- class SUVATCheckerPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="SUVAT Checker Page", font=LARGEFONT)
- self.title.pack(padx=10, pady=10)
- # Instructions explaining to the user what to enter into each entry field
- self.instructions = tk.Label(self, text = """You should have 3 known values, and an unknown value that you want to find
- For each of the boxes below, either:
- 1. The value is known so type it into the box
- 2. The value is unknown and the value you want to find, type in 'A'
- 3. The value is unknown and not the value you want to find, type in 'X'
- Enter your answer in the box by the check button (Please enter your answer to 2 decimal places. No units!)
- A correct answer will earn you 10 points
- An incorrect answer will lose you 1 point
- """)
- self.displacementText = tk.Label(self, text = "Displacement:")
- self.displacementInput = tk.Entry(self, justify="center", width=30)
- self.initialVelocityText = tk.Label(self, text = "Initial Velocity:")
- self.initialVelocityInput = tk.Entry(self, justify="center", width=30)
- self.finalVelocityText = tk.Label(self, text = "Final Velocity:")
- self.finalVelocityInput = tk.Entry(self, justify="center", width=30)
- self.accelerationText = tk.Label(self, text = "Acceleration:")
- self.accelerationInput = tk.Entry(self, justify="center", width=30)
- self.timeTakenText = tk.Label(self, text = "Time Taken:")
- self.timeTakenInput = tk.Entry(self, justify="center", width=30)
- 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!")
- self.userAnswerInput = tk.Entry(self, justify="center", width=30)
- self.submitButton = tk.Button(self,text = "Check", command=lambda: Solve())
- self.instructions.pack(side="top", fill="x")
- self.displacementText.pack(side="top", fill="x", padx=20, pady=5)
- self.displacementInput.pack(side="top")
- self.displacementInput.focus()
- self.initialVelocityText.pack(side="top", fill="x", padx=20, pady=5)
- self.initialVelocityInput.pack(side="top")
- self.finalVelocityText.pack(side="top", fill="x", padx=20, pady=5)
- self.finalVelocityInput.pack(side="top")
- self.accelerationText.pack(side="top", fill="x", padx=20, pady=5)
- self.accelerationInput.pack(side="top")
- self.timeTakenText.pack(side="top", fill="x", padx=20, pady=5)
- self.timeTakenInput.pack(side="top")
- self.userAnswerText.pack(side="top", fill="x", padx=20, pady=5)
- self.userAnswerInput.pack(side="top", pady=5)
- self.submitButton.pack(side="bottom", fill="y", padx=20, pady=5)
- def Solve():
- def deleteEntryFields(): # Clears all the entry fields
- self.displacementInput.delete(0,"end")
- self.initialVelocityInput.delete(0,"end")
- self.finalVelocityInput.delete(0,"end")
- self.accelerationInput.delete(0,"end")
- self.timeTakenInput.delete(0,"end")
- self.userAnswerInput.delete(0,"end")
- def response(message1, message2, score, add): # Displays answer to user
- messagebox.showinfo("{0}".format(message1),"{0}".format(message2), icon = "info")
- if add:
- window.addScore(score)
- messagebox.showinfo("Score Updated","You earnt {0} points for beating PHYSICS".format(score), icon = "info")
- else:
- window.addScore(-score)
- messagebox.showinfo("Score Updated","You lost {0} points for losing to PHYSICS".format(score), icon = "info")
- try:
- s = self.displacementInput.get().lower()
- except:
- s = self.displacementInput.get()
- try:
- u = self.initialVelocityInput.get().lower()
- except:
- u = self.initialVelocityInput.get()
- try:
- v = self.finalVelocityInput.get().lower()
- except:
- v = self.finalVelocityInput.get()
- try:
- a = self.accelerationInput.get().lower()
- except:
- a = self.accelerationInput.get()
- try:
- t = self.timeTakenInput.get().lower()
- except:
- t = self.timeTakenInput.get()
- suvat = [s,u,v,a,t]
- Xcount = 0
- Acount = 0
- numberCount = 0
- for each in suvat:
- if each.lower() == "x": # Increments if an x is found
- Xcount += 1
- elif each.lower() == "a":
- Acount += 1
- if each.isdigit(): # Used to ensure 3 values are numbers and stops the program crashing from attempting to convert letters into float numbers
- numberCount += 1
- elif "-" in each or "." in each: # If there is a negative or decimal number, still increment the numberCount
- numberCount += 1
- if "" in suvat:
- messagebox.showinfo("Error!","Leave no fields blank", icon="warning")
- elif self.userAnswerInput.get() == "":
- messagebox.showinfo("Error!","Enter an answer to check", icon="warning")
- elif Acount == 0:
- messagebox.showinfo("Error!","No value given as 'A'", icon="warning")
- elif Acount > 1:
- messagebox.showinfo("Error!","Only one value can be given as 'A'", icon="warning")
- elif Xcount == 0:
- messagebox.showinfo("Error!","No value given as 'X'", icon="warning")
- elif Xcount > 1:
- messagebox.showinfo("Error!","Only one value can be given as 'X'", icon="warning")
- elif numberCount != 3:
- messagebox.showinfo("Error!","Three values entered must be numbers", icon="warning")
- else:
- Solver = SUVAT(s,u,v,a,t,shortAnswer=True) # Calls the Solving algorithm, passing through the parameters given by the user
- # shortAnswer is True, so only the value is returned, no text
- answer = Solver.initiate() # Returns the answer(s) from the SUVAT equations
- if answer == "None": # If an error occurs in the mathematics, 'None' is returned and this stops an error occuring
- messagebox.showinfo("Error","Invalid details inputted, try again", icon = "warning")
- else:
- if answer == "zeroDivision error":
- messagebox.showinfo("Error","Invalid details inputted, resulting in a calculation involving a division by 0\n\nCheck your numbers", icon = "warning")
- else:
- userAnswer = self.userAnswerInput.get()
- if "," in userAnswer: # Comma suggests the answer has two parts, and so continues onto code that compares two answers
- userAnswer1, userAnswer2 = userAnswer.split(",") # Splits the answers into two variables
- answer1, answer2 = "{:.2f}".format(answer[0]), "{:.2f}".format(answer[1]) # Converts answers from SUVAT() into 2 decimal place variables
- userAnswer1, userAnswer2 = "{:.2f}".format(float(userAnswer1)), "{:.2f}".format(float(userAnswer2))
- if userAnswer1 == answer1:
- if userAnswer2 == answer2:
- response("Correct!!", "You got both answers correct", 15, True)
- deleteEntryFields()
- else: # First correct, second incorrect
- response("Incorrect!!", "Your second answer was wrong, try again", 1, False)
- self.userAnswerInput.delete(",","end")
- else: # First answer is incorrect
- if userAnswer2 == answer2: #
- response("Incorrect!!", "Your first answer was wrong, try again", 1, False)
- self.userAnswerInput.delete(0,",")
- else:
- if userAnswer1 == answer2:# If user enters dual answers in wrong order, compare opposite answers
- if userAnswer2 == answer1:
- response("Correct!!", "You got both answers correct", 15, True)
- deleteEntryFields()
- else: # First answer correct, second incorrect
- response("Incorrect!!", "Your second answer was wrong, try again", 1, False)
- self.userAnswerInput.delete(0,",")
- elif userAnswer2 == answer1:
- response("Incorrect!!", "Your first answer was wrong, try again", 1, False)
- self.userAnswerInput.delete(",","end")
- else:
- response("Incorrect!!", "You got both answers wrong, try again", 2, False)
- self.userAnswerInput.delete(0,"end")
- else: # No comma so only one part, so only us the first element in array 'answer'
- answer = "{0:.2f}".format(answer[0])
- if userAnswer == answer:
- response("Correct!!", "You got the right answer!!", 10, True)
- deleteEntryFields()
- else:
- response("Incorrect!!", "You entered the wrong answer", 1, False)
- self.userAnswerInput.delete(0,"end")
- class SUVATSolverPage(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.title = tk.Label(self, text="SUVAT Solver Page", font=LARGEFONT)
- self.title.pack(padx=10, pady=10)
- self.instructions = tk.Label(self, text = """You should have 3 known values, and an unknown value that you want to find
- For each of the boxes below, either:
- 1. The value is known so type it into the box
- 2. The value is unknown and the value you want to find, type in 'A'
- 3. The value is unknown and not the value you want to find, type in 'X'
- Warning!!! Every answer you seek from this tool with remove 5 points from your account!
- """)
- self.displacementText = tk.Label(self, text = "Displacement:")
- self.displacementInput = tk.Entry(self, justify="center", width=30)
- self.initialVelocityText = tk.Label(self, text = "Initial Velocity:")
- self.initialVelocityInput = tk.Entry(self, justify="center", width=30)
- self.finalVelocityText = tk.Label(self, text = "Final Velocity:")
- self.finalVelocityInput = tk.Entry(self, justify="center", width=30)
- self.accelerationText = tk.Label(self, text = "Acceleration:")
- self.accelerationInput = tk.Entry(self, justify="center", width=30)
- self.timeTakenText = tk.Label(self, text = "Time Taken:")
- self.timeTakenInput = tk.Entry(self, justify="center", width=30)
- self.submitButton = tk.Button(self,text = "Solve", command=lambda: Solve())
- self.instructions.pack(side="top", fill="x", pady=15)
- self.displacementText.pack(side="top", fill="x", padx=20, pady=5)
- self.displacementInput.pack(side="top")
- self.displacementInput.focus()
- self.initialVelocityText.pack(side="top", fill="x", padx=20, pady=5)
- self.initialVelocityInput.pack(side="top")
- self.finalVelocityText.pack(side="top", fill="x", padx=20, pady=5)
- self.finalVelocityInput.pack(side="top")
- self.accelerationText.pack(side="top", fill="x", padx=20, pady=5)
- self.accelerationInput.pack(side="top")
- self.timeTakenText.pack(side="top", fill="x", padx=20, pady=5)
- self.timeTakenInput.pack(side="top")
- self.submitButton.pack(side="top", fill="y", padx=20, pady=10)
- def Solve():
- # Validation Statements
- try:
- s = self.displacementInput.get().lower()
- except:
- s = self.displacementInput.get()
- try:
- u = self.initialVelocityInput.get().lower()
- except:
- u = self.initialVelocityInput.get()
- try:
- v = self.finalVelocityInput.get().lower()
- except:
- v = self.finalVelocityInput.get()
- try:
- a = self.accelerationInput.get().lower()
- except:
- a = self.accelerationInput.get()
- try:
- t = self.timeTakenInput.get().lower()
- except:
- t = self.timeTakenInput.get()
- suvat = [s,u,v,a,t]
- Xcount = 0
- Acount = 0
- numberCount = 0
- for each in suvat:
- if each.lower() == "x":
- Xcount += 1
- elif each.lower() == "a":
- Acount += 1
- if each.isdigit(): # Used to ensure 3 values are numbers and stops the program crashing from attempting to convert letters into float numbers
- numberCount += 1
- elif "-" in each or "." in each:
- numberCount += 1
- if "" in suvat:
- messagebox.showinfo("Error!","Leave no fields blank", icon="warning")
- elif Acount == 0:
- messagebox.showinfo("Error!","No value given as 'A'", icon="warning")
- elif Acount > 1:
- messagebox.showinfo("Error!","Only one value can be given as 'A'", icon="warning")
- elif Xcount == 0:
- messagebox.showinfo("Error!","No value given as 'X'", icon="warning")
- elif Xcount > 1:
- messagebox.showinfo("Error!","Only one value can be given as 'X'", icon="warning")
- elif numberCount != 3:
- messagebox.showinfo("Error!","Three values entered must be numbers", icon="warning")
- else:
- 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
- answer = Solver.initiate()
- if answer == "None":
- messagebox.showinfo("Error","Invalid values inputted, try again", icon = "warning")
- else:
- if answer == "zeroDivision error":
- messagebox.showinfo("Error","Invalid details inputted, resulting in a calculation involving a division by 0\n\nCheck your numbers", icon = "warning")
- else:
- messagebox.showinfo("Answer","{0}".format(answer), icon = "info")
- window.addScore(-5)
- messagebox.showinfo("Score Updated","You lost 5 points for cheating PHYSICS by just wanting an answer", icon = "info")
- deleteEntryFields()
- def deleteEntryFields():
- self.displacementInput.delete(0,"end")
- self.initialVelocityInput.delete(0,"end")
- self.finalVelocityInput.delete(0,"end")
- self.accelerationInput.delete(0,"end")
- self.timeTakenInput.delete(0,"end")
- #############################
- ##### Tkinter Runtime #####
- def exitProgram():
- if messagebox.askokcancel("Quit", "Do you wish to quit?"):
- window.logout()
- try: # If the graph controller is still open, destroy it
- window.frames[interactiveGraphsPage].graphController.destroy()
- except:
- pass
- window.destroy()
- if runProgram: # If any python modules are missing, the Tkinter window will not be called and the program will cease
- window = GUI()
- ani = animation.FuncAnimation(f,animate, interval=500)
- window.protocol("WM_DELETE_WINDOW", exitProgram) # If 'x' in top right corner of GUI window pressed, call exitProgram()
- window.mainloop()
- ###########################
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement