Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import tkinter
- # python gui toolkit
- # used to create windows and GUIs
- import ctypes
- # used to interact C and dll files with python
- # used in my program to access windows SystemMetrics to retrieve screen size
- import socket
- # python network connections module
- # allows network connections in python so the client and server can communicate
- import json
- # this is the python JSON module
- # it allows python to convert string and data structures to and from JSON
- import re
- # the python regular expressions module
- # allows the program to check whether
- # certain characters are used in entry boxes
- import time
- # python module used to track and use time
- # used in program to add delays to some functions
- import math
- # python mathematics module
- # used in program to round numbers up to next integer
- import datetime
- # python module to retrieve date and time
- # used in program to retrieve current date to create new uniform event
- from tkinter import messagebox
- from tkinter import ttk
- # these are subclasses of the GUI toolkit that need to be imported separately
- # tkinter.messagebox is allows the code to create pop-up messageboxes
- # that provide the user with information
- # tkinter.ttk allows the code to create native-style widgets in the GUI
- user32 = ctypes.windll.user32
- screensize = user32.GetSystemMetrics(0),user32.GetSystemMetrics(1)
- # detecting screen size to place window correctly
- #setting ttk styles
- def quicksort(data):
- less = []
- # creates array for the values less than the pivot
- equal = []
- # creates array for values equal to the pivot
- greater = []
- # creates array for values greater than the pivot
- if len(data) > 1:
- pivot = data[0]
- # selects first value of the array as a pivot
- for i in data:
- if i < pivot:
- less.append(i)
- # append any items less than the pivot to a less array
- elif i == pivot:
- equal.append(i)
- # append any items greater than the pivot to an equal array
- elif i > pivot:
- greater.append(i)
- # append any items greater than the pivot
- return quicksort(less)+equal+quicksort(greater)
- # runs recursively as allows for greater efficiency
- else:
- return data
- class SquadBot(tkinter.Tk):
- palette = {"bgblue":"#5d8aa8","white":"#ffffff","darkblue":"#366192",
- "afb":"#4b7da0"}
- def __init__(self):
- tkinter.Tk.__init__(self)
- self.withdraw()
- self.pkey = "18657"
- self.userlvl = tkinter.IntVar()
- self.userlvl.set(1)
- self.userid = tkinter.IntVar()
- self.userid.set(0)
- self.fullname = None
- self.welcomemessage = tkinter.StringVar()
- # <nf>
- self.container = tkinter.Frame(self)
- self.container.pack(side="top",fill="both",expand=True)
- self.container.grid_rowconfigure(0,weight=1)
- self.container.grid_columnconfigure(0,weight=1)
- # creating container for the window
- # setting dictionaries to keep design constant
- self.geometry("700x500+%d+%d"%(screensize[0]/2-400,screensize[1]/2-300))
- self.resizable(0,0)
- # setting location on screen
- self.pages = {} # dictionary of pages
- page = LoginPage(self.container,self)
- # instantiating class of page
- self.pages[LoginPage] = page
- # adding instance to dictionary
- page.grid(row=0,column=0,sticky="nsew")
- # placing instance in window
- self.title("SquadBot") # setting title of window
- self.tk.call('wm', 'iconbitmap', self._w, "resources/crest.ico")
- #changing icon of all windows to crest
- self.protocol("WM_DELETE_WINDOW",self.checkClosing)
- # setting protocol of closing window to run custom function
- self.configure(bg = self.palette["bgblue"])
- # setting background of page to 'bgblue'
- ttk.Style().configure("TButton", relief="flat",background="#72a0c1")
- # setting style of a ttk button
- self.serverConnect(socket.gethostname()) # connect to server
- page = LoginPage(self.container,self) # repeated same as above
- self.pages[LoginPage] = page
- page.grid(row=0,column=0,sticky="nsew")
- # instantiating pages for window
- self.deiconify()
- def showPage(self,slide,old):
- page = slide(self.container,self)
- self.pages = {}
- self.pages[slide] = page
- page.grid(row=0,column=0,sticky="nsew")
- page = self.pages[slide]
- page.tkraise()
- old.grid_forget(self)
- # function shows page given in argument
- def checkClosing(self):
- closing = messagebox.askquestion("Quit","Are you sure you want to quit?")
- # message pop-up
- if closing == "yes":
- self.conn.close()
- self.destroy()
- #quit(0)
- # function checks whether the user actually wants to leave program
- def createImages(self): # this is a separate function, as creating images
- # requires the tkinter runtime to be running, which
- # allows the subclasses to inherit the function and
- # store their own image dictionaries
- self.images = {"bigcrest":tkinter.PhotoImage(file="resources/crest_wo_background_large.png"),
- "smallcrest":tkinter.PhotoImage(file="resources/crest_wo_background_small.png"),
- "quit":tkinter.PhotoImage(file="resources/exiticon2.png"),
- "hide":tkinter.PhotoImage(file="resources/hideicon.png"),
- "mute":tkinter.PhotoImage(file="resources/muteicon.png"),
- "support":tkinter.PhotoImage(file="resources/supporticon.png")}
- def serverConnect(self,ip):
- try:
- self.conn = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # creating socket
- self.conn.connect((ip,8881)) # connecting to correct port
- data = self.conn.recv(1024) # receving data from server
- if data == "Handshake started, authenticate".encode(): # ensuring it is correct program to connect to
- self.conn.sendall("Handshake accepted".encode()) # accepting connection
- spkey = self.conn.recv(1024) # code to send encryption key
- print(spkey.decode()) # <nf>
- self.conn.sendall(self.pkey.encode())
- else:
- tkinter.messagebox.showerror("Error", "Handshake failed") # error message if connection acquired but not server
- except:
- tkinter.messagebox.showerror("Error", "Could not connect to server") # error message if no connection
- self.destroy()
- #quit(0)
- # function tries to connect to server and will close program if it cannot
- def logout(self):
- self.userlvl.set(0)
- self.showPage(LoginPage,MainPage)
- # sets userlvl to 0 and shows login page
- def getuserlvl(self):
- return self.userlvl.get()
- # getter method for userlvl
- def change_text(self,**kwargs):
- # this function sanitises text as the user is typing, preventing attacks
- done = False
- while not done:
- print(kwargs["var"].get())
- if ";" in kwargs["var"].get():
- kwargs["var"].set(kwargs["var"].get().replace(";",","))
- done = False
- self.change_text(**kwargs)
- elif "&&" in kwargs["var"].get():
- kwargs["var"].set(kwargs["var"].get().replace("&&","&"))
- done = False
- self.change_text(**kwargs)
- elif "'" in kwargs["var"].get():
- kwargs["var"].set(kwargs["var"].get().replace("'",""))
- done = False
- self.change_text(**kwargs)
- elif "|" in kwargs["var"].get():
- kwargs["var"].set(kwargs["var"].get().replace("|",""))
- done = False
- self.change_text(**kwargs)
- elif "<" in kwargs["var"].get():
- kwargs["var"].set(kwargs["var"].get().replace("<",""))
- done = False
- self.change_text(**kwargs)
- elif ">" in kwargs["var"].get():
- kwargs["var"].set(kwargs["var"].get().replace(">",""))
- done = False
- self.change_text(**kwargs)
- elif "=" in kwargs["var"].get():
- kwargs["var"].set(kwargs["var"].get().replace("=",""))
- done = False
- self.change_text(**kwargs)
- else:
- done = True
- print("finished")
- try:
- print(1)
- if kwargs["limit"]=="alpha":
- print(2)
- pattern = re.compile(r"[^A-Za-z ]")
- print(pattern)
- print(3)
- print("RE: ",pattern.sub("",kwargs["var"].get()))
- kwargs["var"].set(re.sub(pattern,"",kwargs["var"].get()))
- print(4)
- except:
- pass
- class LoginPage(tkinter.Frame,SquadBot):
- def __init__(self,master,controller):
- tkinter.Frame.__init__(self,master)
- # initialising inherited parent class
- self.createImages()
- # creating an array of images for the class to use
- crestlabel = tkinter.Label(self,image=self.images["bigcrest"],background=self.palette["bgblue"])
- crestlabel.place(x=350,y=0,anchor="n")
- # creating crest image in centre of page
- self.unamelabel = tkinter.Label(self,text="Username:",background=self.palette["bgblue"],font="TkDefaultFont 9 bold")
- self.unamelabel.place(x=250,y=375,anchor="nw")
- # creating a label to show where to enter the username to login
- self.usernamevar = tkinter.StringVar()
- self.usernamevar.trace_add("write", lambda x,y,z: self.change_text(var=self.usernamevar))
- self.unameentry = ttk.Entry(self,text = self.usernamevar)
- self.unameentry.place(x=350,y=395,anchor="n",width=200)
- # creating the text box for the user to enter their username
- pwordlabel = ttk.Label(self,text="Password:",background=self.palette["bgblue"],font="TkDefaultFont 9 bold")
- pwordlabel.place(x=250,y=420,anchor="nw")
- # creating a label to show the user where to enter their password
- self.passwordvar = tkinter.StringVar()
- self.passwordvar.trace_add("write", lambda x,y,z: self.change_text(var=self.passwordvar))
- self.pwordentry = ttk.Entry(self,show="•",text=self.passwordvar)
- self.pwordentry.place(x=350,y=440,anchor="n",width=200)
- # creating a text box for the user to enter their password
- # shows • instead of characters when the user types their password in to prevent people seeing their password
- loginbutton = ttk.Button(self,text="Login",command = lambda: self.login(controller))
- loginbutton.place(x=350,y=468,anchor="n")
- # creates a button that executes LoginPage.Login() with SquadBot as an argument
- self.configure(bg=self.palette["bgblue"])
- # setting background of frame to palette["bgblue"], which is the main background colour of the program
- #notbutton = tkinter.Button(self,text="test",command = lambda: self.shownot(controller))
- #notbutton.place(x=700,y=500,anchor="se")
- # <nf> TESTING NOTIFICATIONS
- def shownot(self,parent):
- window = Notification(self,parent)
- # <nf> MORE NOTIFICATION TESTING
- def login(self,parent):
- username = self.unameentry.get()
- password = self.pwordentry.get()
- # retrieves username and password from the boxes,
- # and replaces any semicolons with a comma
- self.unameentry.delete(0,"end")
- self.pwordentry.delete(0,"end")
- # removes text from entry boxes, so that they are clear for when the user logs out
- data = (username,password)
- # creating tuple from entered data
- jsondata = json.dumps(data)
- # creating a JSON string from tuple
- sendingdata = "l" + jsondata
- # adding an "l" to the front - indicates it is a login request when the server parses it
- parent.conn.sendall(sendingdata.encode())
- # sends the string to the server
- print(sendingdata.encode()) # <nf>
- response = parent.conn.recv(1024).decode()
- # receives the response from the server
- if response[0] == "a": # indicates accepted login
- fullresp = response[1:]
- # removes the 'a' from the front of the data so the rest of it can be decoded
- data = fullresp.split(",")
- # creates an array of strings from the data, splitting it at commas
- parent.userlvl.set(int(data[0]))
- # setting userlevel to set certain functions depending on different users
- parent.fullname = data[2]
- # setting the name of the user to allow better human-computer interaction
- print(parent.fullname)
- print("login successful")
- print(parent.getuserlvl()) # <nf>
- # receives the user data from the server
- parent.userid.set(int(data[1]))
- # sets the user id of the user
- requestdata = parent.conn.recv(1024)
- print(requestdata)
- requests = json.loads(requestdata)
- msg = "There have been responses to your requests:\n\n"
- if len(requests) >0:
- for i in requests:
- msg += i[0]+":"+i[1]+"\n"
- notif = Notification(parent,msg)
- parent.welcomemessage.set("Welcome, {name}!".format(name=parent.fullname))
- # creates a welcome message that is displayed upon loggin in
- parent.showPage(MainPage,LoginPage) # displaying main page, from which other pages can be reached
- elif response[0] == "p": # password incorrect
- tkinter.messagebox.showerror("Error logging in","Password incorrect")
- elif response[0] == "u": # user not found
- tkinter.messagebox.showerror("Error logging in","Username or password incorrect")
- class MainPage(tkinter.Frame,SquadBot): # main page class
- def __init__(self,master,controller): # initialisation function
- tkinter.Frame.__init__(self,master) # initialising inherited class to produce visible object
- self.toptip = tkinter.StringVar()
- self.toptip.set("None")
- self.createImages()
- controller.conn.send("rc".encode()) # retrieves uniform scores to present to the user
- response = controller.conn.recv(1024)
- datadict = json.loads(response)
- data = {}
- print("Datadict:",datadict)
- for i in datadict:
- data[i[1]] = i[0]
- sorteduniform = quicksort(list(data.keys()))
- top5cadets = []
- a=0
- # below code presents the list of top 5 cadets for uniform to the user
- for i in sorteduniform[::-1]:
- if a >= 5:
- break
- controller.conn.send("rn{cid}".format(cid=data[i]).encode())
- jsonname = controller.conn.recv(1024).decode()
- splitname = json.loads(jsonname)
- name = splitname[0]+" "+splitname[1]+" "+splitname[2]
- print("name:",name)
- top5cadets.append(name)
- a+=1
- print("top5:",top5cadets)
- # below code creates a window that allows the user to change password
- def changepword():
- def sendpword():
- if pwordentry.get() == pwordconfirm.get():
- if len(pwordentry.get())>=8:
- controller.conn.send("pc{uid}+{pword}".format(uid=controller.userid.get(),pword=re.sub(";",",",pwordentry.get())).encode())
- self.pwordchange.destroy()
- tkinter.messagebox.showinfo("Success","Password successfully changed")
- else:
- pwordentry.delete(0,"end")
- pwordconfirm.delete(0,"end")
- tkinter.messagebox.showerror("Error","Password must be longer than 8 characters")
- else:
- pwordentry.delete(0,"end")
- pwordconfirm.delete(0,"end")
- tkinter.messagebox.showerror("Error","Passwords do not match")
- self.pwordchange = tkinter.Toplevel(controller)
- self.pwordchange.grab_set()
- self.pwordchange.geometry("200x150")
- userlbl = tkinter.Label(self.pwordchange,text="New Password:")
- userlbl.place(x=100,y=0,anchor="n")
- pwordvar = tkinter.StringVar()
- pwordvar.trace_add("write", lambda x,y,z: self.change_text(var=pwordvar))
- pwordentry = tkinter.Entry(self.pwordchange,text=pwordvar)
- pwordentry.place(x=100,y=30,anchor="n")
- pwordconfirmvar = tkinter.StringVar()
- pwordconfirmvar.trace_add("write", lambda x,y,z: self.change_text(var=pwordconfirmvar))
- pwordconfirmlbl = tkinter.Label(self.pwordchange,text="Confirm Password:")
- pwordconfirmlbl.place(x=100,y=60,anchor="n")
- pwordconfirm = tkinter.Entry(self.pwordchange,text=pwordconfirmvar)
- pwordconfirm.place(x=100,y=90,anchor="n")
- submitbtn = tkinter.Button(self.pwordchange,text="Submit Password",command = lambda: sendpword())
- submitbtn.place(x=100,y=120,anchor="n")
- self.configure(bg=self.palette["bgblue"]) # setting background
- colourbar = tkinter.Frame(self,background=self.palette["darkblue"])
- colourbar.place(x=0,y=0,width=700,height=90,anchor="nw") # accent bar at top of window
- logoutbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Log Out",
- fg="#ffffff",font=("TkDefaultFont","10","bold"),command = lambda: controller.logout())
- logoutbutton.place(height=50,width=100,x=680,y=45,anchor="e") # log out button in bar
- changepwordbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Change \nPassword",
- fg="white",font=("TkDefaultFont","10","bold"),command=lambda: changepword())
- changepwordbutton.place(height=50,width=100,x=560,y=45,anchor="e")
- crestlbl = tkinter.Label(self,image=self.images["smallcrest"],background=self.palette["darkblue"])
- crestlbl.place(x=0,y=0,anchor="nw",width=99,height=135) # squadron crest image in accent bar
- ufsbframe = tkinter.Frame(self,background=self.palette["afb"],borderwidth=2,highlightbackground="white",relief = "groove") # creating area for notifications/announcements
- # uniform scoreboard frame
- if controller.getuserlvl() == 1:
- ufsbframe.place(x=700,y=320,anchor="se",height=200,width=250)
- else:
- ufsbframe.place(x=700,y=90,anchor="ne",height=230,width=250)
- ufsbtitle = tkinter.Label(ufsbframe,text="Top 5 for Uniform:",font=("Arial Black","16","underline"),bg=self.palette["afb"],fg='white')
- ufsbtitle.place(x=5,y=5,anchor="nw") # title for area
- b=0
- for i in top5cadets:
- tkinter.Label(ufsbframe,text=str(b+1)+": "+i,font=("Arial Black","12","bold"),bg=self.palette["afb"],fg="white").place(x=5,y=40+32*b,anchor="nw")
- b+=1
- personalframe = tkinter.Frame(self,background=self.palette["afb"],borderwidth=2,highlightbackground="white",relief="groove")
- if controller.userlvl.get() == 1:# tests if the user is a high enough level to access user management
- personalframe.place(x=700,y=500,anchor="se",width=250,height=180)
- personallbl = tkinter.Label(personalframe,text="Average Uniform Score:",background=self.palette["afb"],foreground="white",font=("Arial Black","12","underline"))
- personallbl.place(x=125,y=22.5,height=45,anchor="center")
- improvementlbl = tkinter.Label(personalframe,text="To improve:",background=self.palette["afb"],foreground="white",font=("Arial Black","12","underline"))
- improvementlbl.place(x=125,y=112.5,height=45,anchor="center")
- improvement = tkinter.Label(personalframe,
- textvariable=self.toptip,
- background=self.palette["afb"],
- foreground="white",
- font=("Arial Black","12","bold"))
- improvement.place(x=125,y=135,anchor="n")
- sqnavgframe = tkinter.Frame(self,background = self.palette["afb"],borderwidth=2,highlightbackground="white",relief="groove")
- sqnavgframe.place(x=700,y=120,anchor="se",width=250,height=30)
- sqnavglbl = tkinter.Label(sqnavgframe,text="Squadron Average:",background=self.palette["afb"],foreground="white",font=("Arial Black","11","underline"))
- sqnavglbl.place(x=0,y=0,anchor="nw",height=25)
- controller.conn.send("rs".encode())
- response = controller.conn.recv(1024).decode()
- data = json.loads(response)
- total = 0
- print(data)
- if data:
- for i in data:
- total+=i[1]
- avg = total/len(data)
- avglbl = tkinter.Label(sqnavgframe,text=round(avg,2),background=self.palette["afb"],foreground="white",font=("Arial Black","11","underline"))
- avglbl.place(x=175,y=0,anchor="nw",height=25)
- else:
- personalframe.place(x=700,y=500,anchor="se",width=250,height=180)
- sqnlbl = tkinter.Label(personalframe,text="Squadron Average \nUniform Score:",background=self.palette["afb"],foreground="white",font=("Arial Black","10","underline"))
- sqnlbl.place(x=125,y=22.5,height=45,anchor="center")
- controller.conn.send("rs".encode())
- response = controller.conn.recv(1024).decode()
- data = json.loads(response)
- total = 0
- print(data)
- if data:
- for i in data:
- total+=i[1]
- avg = total/len(data)
- avglbl = tkinter.Label(personalframe,text=round(avg,2),background=self.palette["afb"],foreground="white",font=("Arial Black","18"))
- avglbl.place(x=125,y=67.5,anchor="center",height=25)
- improvementlbl = tkinter.Label(personalframe,text="Most common improvement:",background=self.palette["afb"],foreground="white",font=("Arial Black","9","underline"))
- improvementlbl.place(x=125,y=112.5,height=45,anchor="center")
- improvement = tkinter.Label(personalframe,
- textvariable=self.toptip,
- background=self.palette["afb"],
- foreground="white",
- font=("Arial Black","12","bold"))
- improvement.place(x=125,y=135,anchor="n")
- def callback(self1,self2,self3): # sorts the data to produce the modal value
- print(self1)
- print(self2)
- print(self3)
- cid = controller.userid.get()
- if controller.userlvl.get() == 1:
- controller.conn.send("rx{cid}".format(cid=cid).encode())
- else:
- controller.conn.send("rx0".encode())
- result = controller.conn.recv(1024).decode()
- print("result:",result)
- arrayraised = json.loads(result)
- print("ARRRR:",arrayraised)
- tipsarray = []
- for i in arrayraised:
- print(i)
- tipsarray.append(i[0])
- data = []
- for i in tipsarray:
- data.append(i)
- print("DaTa:",data)
- sortedtips = quicksort(data)
- nametonum = {}
- print("Sorted:",sortedtips)
- for i in range(len(sortedtips)):
- if sortedtips[i] == sortedtips[i-1]:
- nametonum[sortedtips[i]] += 1
- else:
- nametonum[sortedtips[i]] = 1
- numtoname = {}
- for i in list(nametonum.keys()):
- numtoname[nametonum[i]] = i
- self.toptip.set(numtoname[quicksort(list(numtoname.keys()))[-1]])
- print("freq:",self.toptip.get())
- controller.userid.trace_add("write",callback)
- suppbutt = tkinter.Button(self,text="Request\nSupport",bg=self.palette["white"],command = lambda: controller.showPage(SupportPage,MainPage),justify="center",font=("Arial Black",14))
- suppbutt.place(x=137.5,y=230,anchor="center",width=125,height=125) # button to access support request window
- unibutt = tkinter.Button(self,text="View\nUniform",bg=self.palette["white"],command=lambda:controller.showPage(UniformPage,MainPage),justify="center",font=("Arial Black",14))
- unibutt.place(x=312.5,y=230,height=125,width=125,anchor="center") # button to access uniform scores area
- if controller.getuserlvl() != 1:
- userorgbutt = tkinter.Button(self,text="User Management",bg=self.palette["white"],command = lambda: controller.showPage(UserOrgPage,MainPage),font=("Arial Black",14))
- userorgbutt.place(x=75,y=342.5,anchor="nw",height=125,width=300) # button to access user management page
- welcomelbl = tkinter.Label(colourbar,textvariable=controller.welcomemessage,font=("Arial Black","20","bold"),foreground="white",background=self.palette["darkblue"])
- welcomelbl.place(y=45,x=100,anchor="w")
- # controller.userlvl.trace_add()
- def updatepage(self):
- pass
- class SupportPage(tkinter.Frame,SquadBot): # page for support requests
- def __init__(self,master,controller): # initialising
- tkinter.Frame.__init__(self,master) # initialising inherited class
- self.createImages()
- self.configure(bg=self.palette["bgblue"])
- colourbar = tkinter.Frame(self,background=self.palette["darkblue"])
- colourbar.place(x=0,y=0,width=700,height=90,anchor="nw")
- logoutbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Log Out",
- fg="#ffffff",font=("TkDefaultFont","10","bold"),command = lambda: controller.logout())
- logoutbutton.place(height=50,width=100,x=680,y=45,anchor="e")
- mainscreenbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Back",
- fg="#ffffff",font=("TkDefaultFont","10","bold"),command = lambda: controller.showPage(MainPage,SupportPage))
- mainscreenbutton.place(height=50,width=100,x=560,y=45,anchor="e")
- crestlbl = tkinter.Label(self,image=self.images["smallcrest"],background=self.palette["darkblue"])
- crestlbl.place(x=0,y=0,anchor="nw",width=99,height=135)
- pagelbl = tkinter.Label(colourbar,text="Support",font=("Arial Black","20","bold"),foreground="white",background=self.palette["darkblue"])
- pagelbl.place(y=45,x=100,anchor="w")
- # code above creates accent bar and associated objects
- entrylabel = tkinter.Label(self,text="Please enter your question in the box below",font=("TkDefaultFont","10","bold"),bg=self.palette["bgblue"])
- entrylabel.place(x=150,y=145,anchor="sw") # Label to show where to enter issue
- requestvar = tkinter.StringVar()
- self.entrybox = tkinter.ttk.Entry(self,text=requestvar)
- self.entrybox.place(x=350,y=250,height=200,width=400,anchor="center") # text box to enter issue
- requestvar.trace_add("write", lambda x,y,z: self.change_text(var=requestvar))
- urgencyframe = tkinter.Frame(self)
- urgencyframe.configure(background=self.palette["bgblue"])
- urgencyframe.place(height=30,width=200,x=150,y=360,anchor="nw") # creating frame to contain urgency selector
- sendresponse = tkinter.Button(self,text="Send question",command = lambda: self.sendrequest(controller),font=("Arial Black",10))
- sendresponse.place(height=30,x=375,y=360,anchor="nw",width=150) # button to send response
- urgencylabel = tkinter.Label(urgencyframe,text="Urgency:",background = self.palette["bgblue"],font=("TkDefaultFont","8","bold")) # label to show where to select
- self.urgencyvar = tkinter.IntVar() # creating tkinter variable to use with urgency buttons - must be used with to retrieve value
- self.urgencyvar.set(2)
- highurgency = tkinter.Radiobutton(urgencyframe,text="High",value=1,background=self.palette["bgblue"],activebackground="#ffffff",variable=self.urgencyvar)
- lowurgency = tkinter.Radiobutton(urgencyframe,text="Low",value=2,background=self.palette["bgblue"],activebackground="#ffffff",variable=self.urgencyvar)
- lowurgency.place(x=105,y=15,anchor="w")
- highurgency.place(x=55,y=15,anchor="w")
- urgencylabel.place(x=4,y=15,anchor="w") # placing items in frame
- responsebutton = tkinter.Button(self,text = "Respond to requests",command = lambda: self.respond(controller),font=("Arial Black",10)) # button for higher user levels to respond to requests
- if controller.getuserlvl() >= 2:
- responsebutton.place(x=0,y=500,anchor="sw",height=50,width=200) # testing to see whether user is able to access area or not
- def sendrequest(self,parent): # function to send support request
- request = self.entrybox.get()
- urgency = self.urgencyvar.get()
- if request != "":
- data = (urgency,request)
- jsondata = json.dumps(data)
- sendingdata = "sr" + jsondata
- parent.conn.sendall(sendingdata.encode())
- self.entrybox.delete(0,"end")
- else:
- tkinter.messagebox.showerror("Error","Request cannot be blank")
- def respond(self,parent):
- self.selectorwindow = tkinter.Toplevel()
- self.selectorwindow.geometry("400x300")
- self.selectorwindow.grab_set()
- def scrollfunc(event):
- can.configure(scrollregion=can.bbox("all"),width=400,height=300)
- canvasframe = tkinter.Frame(self.selectorwindow,relief="groove",width=383,height=300)
- canvasframe.place(x=0,y=0)
- def senddata(reply,rid):
- data = (reply,rid)
- jsondata = json.dumps(data)
- sendingdata = "ss" + jsondata
- parent.conn.send(sendingdata.encode())
- self.selectorwindow.destroy
- can = tkinter.Canvas(canvasframe)
- frame = tkinter.Frame(can)
- scrollbar = tkinter.Scrollbar(canvasframe,orient="vertical",command=can.yview)
- can.configure(yscrollcommand=scrollbar.set)
- scrollbar.pack(side="right",fill="y")
- can.pack(side="left")
- can.create_window((0,0),window=frame,anchor="nw")
- frame.bind("<Configure>",scrollfunc)
- parent.conn.send("rh".encode())
- response = parent.conn.recv(1024)
- data = json.loads(response.decode())
- a=0
- print(data)
- controller = parent
- self.responses = []
- if controller.userlvl.get() == 3:
- tkinter.Label(frame,text="Rank").grid(row=a,column=0)
- tkinter.Label(frame,text="Name").grid(row=a,column=1)
- tkinter.Label(frame,text="Request").grid(row=a,column=3)
- tkinter.Label(frame,text="Response").grid(row=a,column=4)
- entryboxes = []
- for i in data:
- a+=1
- self.responses.append(tkinter.StringVar())
- self.responses[-1].set("")
- if controller.userlvl.get() == 3:
- tkinter.Label(frame,text=i[3]).grid(row=a,column=0)
- tkinter.Label(frame,text=i[1]).grid(row=a,column=1)
- tkinter.Label(frame,text=i[2]).grid(row=a,column=2)
- tkinter.Label(frame,text=i[14]).grid(row=a,column=3)
- entryboxes.append(tkinter.Entry(frame,text=self.responses[-1]))
- entryboxes[-1].grid(row=a,column=4)
- tkinter.Button(frame,command = lambda x=i[11],y=entryboxes[-1]: senddata(y.get(),x),text="Reply").grid(row=a,column=5)
- class UniformPage(tkinter.Frame,SquadBot):
- def __init__(self,parent,controller):
- tkinter.Frame.__init__(self,parent)
- self.createImages()
- self.graphs = []
- self.configure(bg=self.palette["bgblue"])
- colourbar = tkinter.Frame(self,background=self.palette["darkblue"])
- colourbar.place(x=0,y=0,width=700,height=90,anchor="nw")
- logoutbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Log Out",
- fg="#ffffff",font=("TkDefaultFont","10","bold"),command = lambda: controller.logout())
- logoutbutton.place(height=50,width=100,x=680,y=45,anchor="e")
- mainscreenbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Back",
- fg="#ffffff",font=("TkDefaultFont","10","bold"),command = lambda: controller.showPage(MainPage,UniformPage))
- mainscreenbutton.place(height=50,width=100,x=560,y=45,anchor="e")
- crestlbl = tkinter.Label(self,image=self.images["smallcrest"],background=self.palette["darkblue"])
- crestlbl.place(x=0,y=0,anchor="nw",width=99,height=135)
- pagelbl = tkinter.Label(colourbar,text="Uniform",font=("Arial Black","20","bold"),foreground="white",background=self.palette["darkblue"])
- pagelbl.place(y=45,x=100,anchor="w")
- if controller.getuserlvl() == 1:
- uniform = tkinter.Button(self,text = "View my own uniform scores",command = lambda: self.returnowndata(controller),justify="center")
- uniform.place(x=50,y=150,anchor="nw",width = 200,height = 125)
- sqnudata = tkinter.Button(self,text="View average uniform \nscores for the squadron",command = lambda: self.returnsqndata(controller),justify="center")
- sqnudata.place(x=50,y=450,anchor="sw",width=200,height=125)
- else:
- uniform = tkinter.Button(self,text="Create new \nuniform record",command = lambda: self.newnight(controller),justify="center")
- uniform.place(x=50,y=150,anchor="nw",height=80,width=200)
- cdtdata = tkinter.Button(self,text="Choose data for specific cadet",command = lambda: self.returncadetdata(controller))
- cdtdata.place(x=50,y=300,anchor="w",height=80,width=200)
- sqnudata = tkinter.Button(self,text="View average uniform \nscores for the squadron",command = lambda: self.returnsqndata(controller),justify="center")
- sqnudata.place(x=50,y=450,anchor="sw",height=80,width=200)
- self.returnsqndata(controller,delay=0)
- def choosecadet(self,num,name,controller):
- for i in self.graphs:
- i.place_forget()
- print(num)
- controller.conn.send(("rz{c}".format(c=num)).encode())
- self.selectorwindow.destroy()
- jsonscores = controller.conn.recv(1024)
- datanest = json.loads(jsonscores)
- print(datanest)
- data = self.cleansedatenest(datanest)
- cdtgraph = Graph(self,400,300,data,700,100,"ne",maxi=6,title="Uniform Scores for {nam}".format(nam=name),goal=3)
- self.graphs.append(cdtgraph)
- controller.conn.send("rx{cid}".format(cid=num).encode())
- result = controller.conn.recv(1024).decode()
- arrayraised = json.loads(result)
- tipsarray = []
- for i in arrayraised:
- print(i)
- tipsarray.append(i[0])
- data = tipsarray
- print("DaTa:",data)
- sortedtips = quicksort(data)
- nametonum = {}
- print("Sorted:",sortedtips)
- for i in range(len(sortedtips)):
- if sortedtips[i] == sortedtips[i-1]:
- nametonum[sortedtips[i]] += 1
- else:
- nametonum[sortedtips[i]] = 1
- numtoname = {}
- for i in list(nametonum.keys()):
- numtoname[nametonum[i]] = i
- tip = numtoname[quicksort(list(numtoname.keys()))[-1]]
- self.graphs.append(tkinter.Label(self,text="To Improve: {improv}".format(improv=tip),font=("Arial Black",12),foreground="white",background=self.palette["bgblue"]))
- self.graphs[-1].place(anchor="s",x=500,y=470)
- def cleansedatenest(self,datanest):
- b=0
- for i in datanest:
- print(datanest[b][0])
- datanest[b][0] = (datanest[b][0])[8:]+"-"+(datanest[b][0])[5:7]
- b+=1
- data = {}
- for i in datanest:
- data[i[0]] = i[1]
- return data
- def returncadetdata(self,parent):
- self.selectorwindow = tkinter.Toplevel()
- self.selectorwindow.geometry("200x200")
- def scrollfunc(event):
- can.configure(scrollregion=can.bbox("all"),width=200,height=200)
- canvasframe = tkinter.Frame(self.selectorwindow,relief="groove",width=183,height=200)
- canvasframe.place(x=0,y=0)
- can = tkinter.Canvas(canvasframe)
- frame = tkinter.Frame(can)
- scrollbar = tkinter.Scrollbar(canvasframe,orient="vertical",command=can.yview)
- can.configure(yscrollcommand=scrollbar.set)
- scrollbar.pack(side="right",fill="y")
- can.pack(side="left")
- can.create_window((0,0),window=frame,anchor="nw")
- frame.bind("<Configure>",scrollfunc)
- parent.conn.send("ru".encode())
- response = parent.conn.recv(1024)
- data = json.loads(response.decode())
- a=0
- print(data)
- controller = parent
- for i in data:
- tkinter.Label(frame,text=i[0]).grid(row=a,column=0)
- tkinter.Label(frame,text=i[1]).grid(row=a,column=1)
- tkinter.Label(frame,text=i[2]).grid(row=a,column=2)
- name = i[0]+" "+i[1]+" "+i[2]
- tkinter.Button(frame,text="Select",command=lambda b=i[3], nom=name: self.choosecadet(b,nom,controller)).grid(row=a,column=3)
- print("button",i,":",i[3])
- a+=1
- def returnsqndata(self,parent,**kwargs):
- for i in self.graphs:
- i.place_forget()
- parent.conn.send("rs".encode())
- jsonscores = parent.conn.recv(1024)
- datanest = json.loads(jsonscores)
- data = self.cleansedatenest(datanest)
- if "delay" in kwargs:
- sqngraph = Graph(self,400,300,data,700,100,"ne",maxi=6,title="Average uniform for 1000(Blyth) Squadron",delay=kwargs["delay"],goal=4)
- print("nodelay")
- else:
- sqngraph = Graph(self,400,300,data,700,100,"ne",maxi=6,title="Average uniform for 1000(Blyth) Squadron",goal=4)
- self.graphs.append(sqngraph)
- parent.conn.send("rx0".encode())
- result = parent.conn.recv(1024).decode()
- arrayraised = json.loads(result)
- tipsarray = []
- for i in arrayraised:
- print(i)
- tipsarray.append(i[0])
- data = tipsarray
- print("DaTa:",data)
- sortedtips = quicksort(data)
- nametonum = {}
- print("Sorted:",sortedtips)
- for i in range(len(sortedtips)):
- if sortedtips[i] == sortedtips[i-1]:
- nametonum[sortedtips[i]] += 1
- else:
- nametonum[sortedtips[i]] = 1
- numtoname = {}
- for i in list(nametonum.keys()):
- numtoname[nametonum[i]] = i
- tip = numtoname[quicksort(list(numtoname.keys()))[-1]]
- self.graphs.append(tkinter.Label(self,text="Main improvement required: {improv}".format(improv=tip),font=("Arial Black",12),foreground="white",background=self.palette["bgblue"]))
- self.graphs[-1].place(anchor="s",x=500,y=470)
- def returnowndata(self,parent):
- for i in self.graphs:
- i.place_forget()
- controller.conn.send(("rz{c}".format(c=parent.userid.get())).encode())
- self.selectorwindow.destroy()
- jsonscores = controller.conn.recv(1024)
- datanest = json.loads(jsonscores)
- print(datanest)
- data = self.cleansedatenest(datanest)
- cdtgraph = Graph(self,400,300,data,700,100,"ne",maxi=6,title="Uniform Scores for {nam}".format(nam=parent.fullname),goal=3)
- self.graphs.append(cdtgraph)
- controller.conn.send("rx{cid}".format(cid=parent.userid.get()).encode())
- result = controller.conn.recv(1024).decode()
- arrayraised = json.loads(result)
- tipsarray = []
- for i in arrayraised:
- print(i)
- tipsarray.append(i[0])
- data = tipsarray
- print("DaTa:",data)
- sortedtips = quicksort(data)
- nametonum = {}
- print("Sorted:",sortedtips)
- for i in range(len(sortedtips)):
- if sortedtips[i] == sortedtips[i-1]:
- nametonum[sortedtips[i]] += 1
- else:
- nametonum[sortedtips[i]] = 1
- numtoname = {}
- for i in list(nametonum.keys()):
- numtoname[nametonum[i]] = i
- tip = numtoname[quicksort(list(numtoname.keys()))[-1]]
- self.graphs.append(tkinter.Label(self,text="To Improve: {improv}".format(improv=tip),font=("Arial Black",12),foreground="white",background=self.palette["bgblue"]))
- self.graphs[-1].place(anchor="s",x=500,y=470)
- def newnight(self,parent):
- def senddata(parent):
- date = datetime.datetime.today().strftime('%Y-%m-%d')
- userdata = []
- for i in range(len(data)):
- if self.absent[i].get() == True:
- absent = "X"
- self.tips[i].set("NULL")
- score = "NULL"
- else:
- absent = "/"
- score = self.score[i].get()
- user = (data[i][3],date,absent,score,self.tips[i].get())
- userdata.append(user)
- sendingdata = json.dumps(userdata)
- encodingdata = "<"+sendingdata+">"
- parent.conn.send(encodingdata.encode())
- returned = parent.conn.recv(1024)
- if returned.decode() == "DAR":
- tkinter.messagebox.showerror("Error","Data already recorded for today")
- elif returned.decode() == "DSU":
- tkinter.messagebox.showinfo("Success","Uniform data successfully uploaded")
- self.selectorwindow.destroy()
- parent.conn.send("sa".encode())
- endofdata = False
- data=""
- while not endofdata:
- received = parent.conn.recv(1024)
- decoded = received.decode()
- print("received:",decoded)
- data = data.join(decoded)
- if data[-1] == ">":
- endofdata = True
- jsondata = data[1:-1]
- data = json.loads(jsondata)
- for i in data:
- print(i)
- def closingwindow():
- tkinter.messagebox.showerror("Error","Uniform scores must be submitted in order to close this window")
- self.selectorwindow = tkinter.Toplevel()
- self.selectorwindow.geometry("400x240+200+200")
- self.selectorwindow.tk.call('wm', 'iconbitmap', self.selectorwindow._w, "resources/crest.ico")
- self.selectorwindow.configure(bg=self.palette["bgblue"])
- self.selectorwindow.protocol("WM_DELETE_WINDOW",closingwindow)
- self.selectorwindow.grab_set()
- def scrollfunc(event):
- can.configure(scrollregion=can.bbox("all"),width=400,height=200)
- canvasframe = tkinter.Frame(self.selectorwindow,relief="groove",width=383,height=200)
- canvasframe.place(x=0,y=0)
- can = tkinter.Canvas(canvasframe)
- frame = tkinter.Frame(can)
- scrollbar = tkinter.Scrollbar(canvasframe,orient="vertical",command=can.yview)
- can.configure(yscrollcommand=scrollbar.set)
- scrollbar.pack(side="right",fill="y")
- can.pack(side="left")
- can.create_window((0,0),window=frame,anchor="nw")
- frame.bind("<Configure>",scrollfunc)
- submitbutton = tkinter.ttk.Button(self.selectorwindow,text="Submit",command = lambda: senddata(parent))
- submitbutton.place(x=200,y=237.5,anchor="s",height=30)
- a=0
- print(data)
- controller = parent
- self.absent = []
- self.score = []
- self.tips = []
- tkinter.Label(frame,text="Rank").grid(row=a,column=0)
- tkinter.Label(frame,text="Name").grid(row=a,column=1)
- tkinter.Label(frame,text="Absent/Civvies?").grid(row=a,column=3)
- # civvies = colloquial name for cilivian clothing
- # on other official programs, it is also used in this form
- tkinter.Label(frame,text="Score").grid(row=a,column=4)
- tkinter.Label(frame,text="To improve").grid(row=a,column=5)
- for i in data:
- a+=1
- tkinter.Label(frame,text=i[0]).grid(row=a,column=0)
- tkinter.Label(frame,text=i[1]).grid(row=a,column=1)
- tkinter.Label(frame,text=i[2]).grid(row=a,column=2)
- name = i[0]+" "+i[1]+" "+i[2]
- self.absent.append(tkinter.BooleanVar())
- self.absent[-1].set(False)
- tkinter.Checkbutton(frame,variable=self.absent[-1]).grid(row=a,column=3)
- self.score.append(tkinter.Spinbox(frame,from_=0,to=6))
- self.score[-1].grid(row=a,column=4)
- self.tips.append(tkinter.StringVar())
- self.tips[-1].set("Beret")
- tkinter.OptionMenu(frame,self.tips[-1],"Beret","Shirt","Brassard","Trousers","Shoes","Turnout").grid(row=a,column=5)
- print("button",i,":",i[3])
- class UserOrgPage(tkinter.Frame,SquadBot):
- def __init__(self,parent,controller):
- tkinter.Frame.__init__(self,parent)
- self.createImages() # creates array of images
- self.configure(bg=self.palette["bgblue"])
- colourbar = tkinter.Frame(self,background=self.palette["darkblue"])
- colourbar.place(x=0,y=0,width=700,height=90,anchor="nw")
- logoutbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Log Out",
- fg="#ffffff",font=("TkDefaultFont","10","bold"),command = lambda: controller.logout())
- logoutbutton.place(height=50,width=100,x=680,y=45,anchor="e")
- mainscreenbutton = tkinter.Button(colourbar,background=self.palette["darkblue"],text="Back",
- fg="#ffffff",font=("TkDefaultFont","10","bold"),command = lambda: controller.showPage(MainPage,UserOrgPage))
- mainscreenbutton.place(height=50,width=100,x=560,y=45,anchor="e")
- crestlbl = tkinter.Label(self,image=self.images["smallcrest"],background=self.palette["darkblue"])
- crestlbl.place(x=0,y=0,anchor="nw",width=99,height=135)
- pagelbl = tkinter.Label(colourbar,text="User Management",font=("Arial Black","20","bold"),foreground="white",background=self.palette["darkblue"])
- pagelbl.place(y=45,x=100,anchor="w")
- # above code is the same setup as other pages
- useraddframe = tkinter.Frame(self,background = self.palette["afb"])
- useraddframe.place(x=10,y=145,anchor="nw",width=375,height=300)
- # creates frame to add new user
- newubutton = tkinter.Button(useraddframe,text="Add new user",command=lambda: self.addnewuser(controller))
- newubutton.place(x=187.5,y=260,height=25,width=80,anchor="n")
- forenamelbl = tkinter.Label(useraddframe,text="Forename:",bg=self.palette["afb"])
- forenamelbl.place(x=25,y=15,anchor="nw")
- self.forenamevar = tkinter.StringVar()
- self.forenamevar.trace_add("write", lambda x,y,z: self.change_text(var=self.forenamevar))
- self.forenameentry = tkinter.Entry(useraddframe,text=self.forenamevar)
- self.forenameentry.place(x=100,y=40,anchor="n",width=150)
- self.usernamevar = tkinter.StringVar()
- self.usernamevar.trace_add("write", lambda x,y,z: self.change_text(var=self.usernamevar))
- usernamelbl = tkinter.Label(useraddframe,text="Username:",bg=self.palette["afb"])
- usernamelbl.place(x=200,y=15,anchor="nw")
- self.usernameentry = tkinter.Entry(useraddframe,text = self.usernamevar)
- self.usernameentry.place(x=275,y=40,anchor="n",width=150)
- surnamelbl = tkinter.Label(useraddframe,text="Surname:",bg=self.palette["afb"])
- surnamelbl.place(x=25,y=65,anchor="nw")
- self.surnamevar = tkinter.StringVar()
- self.surnamevar.trace_add("write", lambda x,y,z: self.change_text(var=self.surnamevar))
- self.surnameentry = tkinter.Entry(useraddframe,text=self.surnamevar)
- self.surnameentry.place(x=100,y=90,width=150,anchor="n")
- passwordlbl = tkinter.Label(useraddframe,text="Password:",bg=self.palette["afb"])
- passwordlbl.place(x=200,y=65,anchor="nw")
- self.passwordvar = tkinter.StringVar()
- self.passwordvar.trace_add("write", lambda x,y,z: self.change_text(var=self.passwordvar))
- self.passwordentry = tkinter.Entry(useraddframe,text=self.passwordvar)
- self.passwordentry.place(x=275,y=90,anchor="n",width=150)
- self.pwordcheckvar = tkinter.StringVar()
- self.pwordcheckvar.trace_add("write", lambda x,y,z: self.change_text(var=self.pwordcheckvar))
- passwordchecklbl = tkinter.Label(useraddframe,text="Confirm Password:",bg=self.palette["afb"])
- passwordchecklbl.place(x=200,y=115,anchor="nw")
- self.passwordcheck = tkinter.Entry(useraddframe,text=self.pwordcheckvar)
- self.passwordcheck.place(x=275,y=140,anchor="n",width=150)
- self.gender = tkinter.StringVar()
- genderlabel = tkinter.Label(useraddframe,text="Gender:",bg=self.palette["afb"])
- genderlabel.place(x=25,y=120,anchor="nw")
- genderentry = tkinter.OptionMenu(useraddframe,self.gender,"Male","Female")
- genderentry.configure(highlightbackground=self.palette["afb"])
- genderentry.place(x=100,y=115,anchor="nw",width=75)
- self.flight = tkinter.StringVar()
- flightlabel = tkinter.Label(useraddframe,text="Flight:",bg=self.palette["afb"])
- flightlabel.place(x=25,y=155,anchor="nw")
- flightentry = tkinter.OptionMenu(useraddframe,self.flight,"A","B","T")
- flightentry.configure(highlightbackground=self.palette["afb"])
- flightentry.place(x=100,y=150,anchor="nw",width=75)
- self.rank = tkinter.StringVar()
- ranklabel = tkinter.Label(useraddframe,text="Rank:",bg=self.palette["afb"])
- ranklabel.place(x=25,y=190,anchor="nw")
- rankentry = tkinter.OptionMenu(useraddframe,self.rank,"Cdt","Cpl","Sgt","FS","CWO")
- rankentry.configure(highlightbackground=self.palette["afb"])
- rankentry.place(x=100,y=185,anchor="nw",width=75)
- def changerankoptions(): # changes the rank options if the user is a staff member, as staff have different ranks to cadets
- print("rankchanging")
- cadet = staff.get()
- print(cadet)
- staff_ranks = ("CI","SI","Sgt (ATC)","FS (ATC)","WO (ATC)","Plt Off","Fg Off","Flt Lt","Sqn Ldr","Wg Cdr","Gp Capt")
- cadet_ranks = ("Cdt","Cpl","Sgt","FS","CWO")
- rankentry["menu"].delete(0,"end")
- flightentry["menu"].delete(0,"end")
- if cadet:
- for i in staff_ranks:
- rankentry["menu"].add_command(label=i,command=tkinter._setit(self.rank, i))
- flightentry["menu"].add_command(label="S",command=tkinter._setit(self.flight,"S"))
- self.flight.set("S")
- self.rank.set("CI")
- else:
- for i in cadet_ranks:
- rankentry["menu"].add_command(label=i,command=tkinter._setit(self.rank, i))
- for i in ("A","B","T"):
- flightentry["menu"].add_command(label=i,command=tkinter._setit(self.flight, i))
- self.flight.set("A")
- self.rank.set("Cdt")
- stafflbl = tkinter.Label(useraddframe,text="Staff? :",bg=self.palette["afb"])
- stafflbl.place(x=200,y=190)
- staff = tkinter.BooleanVar()
- staff.set(False)
- staffbtn = tkinter.Checkbutton(useraddframe,variable=staff,command=lambda:changerankoptions())
- staffbtn.place(x=275,y=190)
- doblabel = tkinter.Label(useraddframe,text="D.O.B:",bg=self.palette["afb"])
- doblabel.place(x=25,y=225,anchor="nw")
- self.month = tkinter.StringVar()
- self.month.set("Jan")
- self.dayentry = tkinter.Spinbox(useraddframe,from_=1,to=31)
- self.dayentry.place(x=103,y=220,width=50,height=25)
- self.monthdict = {"Jan":1,"Feb":2,"Mar":3,"Apr":4,"May":5,"Jun":6,"Jul":7,"Aug":8,"Sep":9,"Oct":10,"Nov":11,"Dec":12}
- monthentry = tkinter.OptionMenu(useraddframe,self.month,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec")
- monthentry.configure(highlightbackground=self.palette["afb"],indicatoron=False)
- monthentry.place(x=188,y=218,width=60,height=30,anchor="n")
- self.year = tkinter.StringVar()
- self.year.set("2000")
- self.yearentry = tkinter.Spinbox(useraddframe,from_=1930,to=int(datetime.datetime.today().strftime("%Y"))-11,textvariable=self.year)
- self.yearentry.place(x=223,y=220,width=50,height=25)
- # above code creates buttons and boxes to allows entry of a new user
- manageuserbtn = tkinter.Button(self,text="Manage Users",command=lambda:self.manageusers(controller),font=("Arial Black",14))
- manageuserbtn.place(x=420,y=185,width=250,height=50,anchor="w")
- controller.conn.send("rr".encode())
- response = controller.conn.recv(1024).decode()
- data = json.loads(response)
- officernumber = staffnumber = nconumber = cadetnumber = 0
- for i in data:
- rank = i[0]
- if rank in ("Plt Off","Fg Off","Flt Lt","Sqn Ldr","Wg Cdr","Gp Capt"):
- officernumber+=1
- elif rank in ("CI","SI","Sgt (ATC)","FS (ATC)","WO (ATC)"):
- staffnumber+=1
- elif rank in ("Cpl","Sgt","FS","CWO"):
- nconumber+=1
- elif rank == "Cdt":
- cadetnumber+=1
- # counts total number of users to display how many of each type there are
- usernoframe = tkinter.Frame(self,background = self.palette["afb"])
- usernoframe.place(x=420,y=245,anchor="nw",width=250,height=200)
- usernotitle = tkinter.Label(usernoframe,text="Users",background=self.palette["afb"],foreground="white",font=("Arial Black","15","underline"))
- noofusers = tkinter.Label(usernoframe,text="""
- Officers: {offno}
- Other Staff: {staffno}
- NCOs: {ncono}
- Cadets: {cadetno}""".format(offno=officernumber,staffno=staffnumber,ncono=nconumber,cadetno=cadetnumber)
- ,background = self.palette["afb"],foreground="white",font=("Arial Black","12"),justify="left")
- usernotitle.place(x=125,y=10,anchor="n")
- noofusers.place(x=125,y=50,anchor="n")
- # displays number of users
- def manageusers(self,parent):
- parent.conn.send("d".encode())
- # client wishes to change details of a user
- endofdata = False
- data=""
- while not endofdata:
- received = parent.conn.recv(1024)
- decoded = received.decode()
- print("received:",decoded)
- data = data.join(decoded)
- if data[-1] == ">":
- endofdata = True
- jsondata = data[1:-1]
- data = json.loads(jsondata)
- # above code receives data and decodes it to usable format
- for i in data:
- print(i)
- self.managementwindow = tkinter.Toplevel()
- self.managementwindow.geometry("400x200+200+200")
- self.managementwindow.tk.call('wm', 'iconbitmap', self.managementwindow._w, "resources/crest.ico")
- self.managementwindow.configure(bg=self.palette["bgblue"])
- self.managementwindow.grab_set()
- # creates extra window to select users to edit
- def scrollfunc(event):
- can.configure(scrollregion=can.bbox("all"),width=383,height=200)
- canvasframe = tkinter.Frame(self.managementwindow,relief="groove",width=383,height=200)
- canvasframe.place(x=0,y=0)
- can = tkinter.Canvas(canvasframe)
- frame = tkinter.Frame(can)
- scrollbar = tkinter.Scrollbar(canvasframe,orient="vertical",command=can.yview)
- can.configure(yscrollcommand=scrollbar.set)
- scrollbar.pack(side="right",fill="y")
- can.pack(side="left")
- can.create_window((0,0),window=frame,anchor="nw")
- frame.bind("<Configure>",scrollfunc)
- a=0
- print(data)
- controller = parent
- def selectuser(uid,parent,num):
- option = self.selection[num-1].get()
- print(option,uid)
- if option == "Delete User": # this code allows a user to be deleted
- checking = tkinter.messagebox.askquestion("Delete User","Are you sure you want to delete this user? It cannot be undone")
- if checking == "yes":
- parent.conn.send("px{userid}".format(userid=uid).encode())
- response = parent.conn.recv(1024).decode()
- if response == "UFD":
- tkinter.messagebox.showinfo("Success","User Successfully Deleted")
- self.managementwindow.destroy()
- else:
- tkinter.messagebox.showerror("Error","An error occured. Try again")
- elif option == "Reset Password": # this code resets a user's password and receoves a randomly-generated one
- checking = tkinter.messagebox.askquestion("Reset Password","Are you sure you want to reset this user's password?")
- if checking == "yes":
- parent.conn.send("pp{userid}".format(userid=uid).encode())
- npw = parent.conn.recv(1024).decode()
- print(npw)
- print(npw[:3])
- if npw[:3] == "npw":
- tkinter.messagebox.showinfo("New Password","The new password for this user is: {pw}\nIt is strongly advised they write this down.".format(pw=npw[3:]))
- elif option == "Edit User":
- usereditwindow = tkinter.Toplevel(parent)
- # creates a separate window to the main program
- usereditwindow.grab_set()
- # makes it so that the main window cannot be interacted with unil this window has been closed
- usereditwindow.geometry("200x140")
- # setting size of window
- usereditwindow.resizable(0,0)
- # preventing the window from being resized
- userlbl = tkinter.Label(usereditwindow,text="Which attribute would \nyou like to change?")
- userlbl.place(x=100,y=0,anchor="n")
- attribute = tkinter.StringVar()
- newval = tkinter.StringVar()
- newval.trace_add("write", lambda x,y,z: self.change_text(var=newval,limit="alpha"))
- attribute.set("Forename")
- attributebox = tkinter.OptionMenu(usereditwindow,attribute,"Forename","Surname","Gender","Rank","Flight","Username")
- attributebox.place(x=100,y=40,anchor="n")
- self.entrywidg = []
- entrybox = tkinter.Entry(usereditwindow,text=newval)
- entrybox.place(x=100,y=70,anchor="n")
- submit = tkinter.Button(usereditwindow,text="Submit Changes",command = lambda: submitdata())
- submit.place(x=100,y=100,anchor="n")
- def submitdata():
- print("helllllllo")
- ranks = ("Cdt","Cpl","Sgt","FS","CWO","CI","SI","Sgt (ATC)","FS (ATC)","WO (ATC)","Plt Off","Fg Off","Flt Lt","Sqn Ldr","Wg Cdr","Gp Capt")
- varchanging = attribute.get()
- newdata = entrybox.get()
- if varchanging == "Gender" and len(newdata)!=1:
- tkinter.messagebox.showerror("Error","Gender must be 1 character")
- return 0
- elif varchanging == "Rank" and newdata not in ranks:
- tkinter.messagebox.showerror("Error","Not a valid rank. Valid ranks are:\n Cdt, Cpl, Sgt, FS, CWO,\n CI, SI, Sgt (ATC), WO (ATC), Plt Off,\n Fg Off, Flt Lt, Sqn Ldr, Wg Cdr, Gp Capt")
- return 0
- elif newdata == "":
- tkinter.messagebox.showerror("Error","Data field cannot be empty")
- return 0
- parent.conn.send("pd{cid}+{typ}+{dat}".format(typ=varchanging,dat=newdata,cid=uid).encode())
- response = parent.conn.recv(1024).decode()
- if response == "DCS":
- tkinter.messagebox.showinfo("Success","Details successfully changed")
- usereditwindow.destroy()
- elif response == "UAE":
- tkinter.messagebox.showerror("Error","That username already exists")
- self.selection = []
- tkinter.Label(frame,text="Rank").grid(row=a,column=0)
- tkinter.Label(frame,text="Name").grid(row=a,column=1)
- tkinter.Label(frame,text="Option").grid(row=a,column=3)
- self.buttons = []
- for i in data:
- a+=1
- tkinter.Label(frame,text=i[0]).grid(row=a,column=0)
- tkinter.Label(frame,text=i[1]).grid(row=a,column=1)
- tkinter.Label(frame,text=i[2]).grid(row=a,column=2)
- name = i[0]+" "+i[1]+" "+i[2]
- self.selection.append(tkinter.StringVar())
- self.selection[-1].set("Edit User")
- tkinter.OptionMenu(frame,self.selection[-1],"Edit User","Reset Password","Delete User").grid(row=a,column=3)
- print("button",i,":",i[3])
- self.buttons.append(tkinter.Button(frame,command = lambda x=i[3],y=a: selectuser(x,parent,y),text="Select"))
- self.buttons[-1].grid(row=a,column=4)
- def addnewuser(self,parent):
- forename = self.forenameentry.get()
- surname = self.surnameentry.get()
- username = self.usernameentry.get()
- password = self.passwordentry.get()
- password2 = self.passwordcheck.get()
- flight = self.flight.get()
- rank = self.rank.get()
- gender = self.gender.get()
- if gender == "Male":
- gender = "M"
- else:
- gender = "F"
- dob = self.getdob()
- if password == password2:
- if len(password)>=8:
- userdata = (forename,surname,rank,flight,gender,dob,username,password)
- jsondata = json.dumps(userdata)
- sendingdata = "su" + jsondata
- parent.conn.send(sendingdata.encode())
- response = parent.conn.recv(1024).decode()
- if response == "UAS":
- self.forenameentry.delete(0,"end")
- self.surnameentry.delete(0,"end")
- self.usernameentry.delete(0,"end")
- self.passwordentry.delete(0,"end")
- self.passwordcheck.delete(0,"end")
- tkinter.messagebox.showinfo("Success","User successfully added")
- elif response == "UAE":
- tkinter.messagebox.showerror("Error","That username is taken")
- else:
- tkinter.messagebox.showerror("Error","Password must be 8 characters or longer")
- else:
- tkinter.messagebox.showerror("Error","Passwords do not match")
- def checkcontent(string):
- pattern = ""
- def getdob(self):
- day = self.dayentry.get()
- month = self.month.get()
- monthnum = self.monthdict[month]
- try:
- print(str(monthnum)[1])
- monthnum = str(monthnum)
- except:
- monthnum = "0"+str(monthnum)
- year = self.yearentry.get()
- datestr = str(year)+"-"+str(monthnum)+"-"+str(day)
- print(datestr)
- return datestr
- class Notification(tkinter.Toplevel,SquadBot):
- def __init__(self,parent,notif):
- tkinter.Toplevel.__init__(self,parent)
- self.geometry("400x210+%d+%d"%(screensize[0]-265,screensize[1]-215))
- self.overrideredirect(1)
- self.attributes("-topmost",1)
- notification = notif
- self.configure(borderwidth=5,relief="ridge")
- tkinter.Label(self,text=notification,anchor="nw",justify="left",font=("TkDefaultFont 10")).place(x=5,y=5,anchor="nw",height=110,width=240)
- self.after(60000,self.destroy)
- self.deiconify()
- self.title("GOODBYE")
- class Graph(tkinter.Canvas):
- def __init__(self,parent,width,height,dataunclean,xcoord,ycoord,anch,**kwargs):
- tkinter.Canvas.__init__(self,parent)
- # initialises the tkinter canvas class to provide a drawing surface
- self.configure(width=width,height=height)
- # setting width and height of canvas to arguments provided
- self.create_line(50,(height-50),(width-50),(height-50),width=2)
- self.create_line(50,50,50,height-50,width=2)
- # drawing the axes of the graph
- graph_width = width-100
- graph_height = height-100
- # setting width of the graph within the canvas
- self.place(x=xcoord,y=ycoord,anchor=anch)
- # placing the canvas at the coordinates provided in the arguments
- if isinstance(dataunclean,dict):
- # tests if dataunclean is a dictionary
- # dataunclean is the raw data coming, unclean as it may contain None or string values
- a = 0
- uncleanvalues = list(dataunclean.values())
- # creates list from dataunclean's values
- data = []
- for i in uncleanvalues:
- if isinstance(i,int):
- data.append(uncleanvalues[a])
- # appends if value is an integer
- elif isinstance(i,float):
- data.append(uncleanvalues[a])
- # appends if value is a float
- else:
- try:
- data.append((uncleanvalues[a-1]+uncleanvalues[a+1])/2)
- # if not integer, take average values of weeks before and after
- except IndexError:
- data.append(uncleanvalues[a-1])
- # if week after does not exist (latest week value), take value of week before
- except TypeError:
- data.append(uncleanvalues[0])
- # if week before and after do not exist, set value as first recorded value
- # there will always be a first recorded value, as users will only be added when they are present, and therefore will have a score
- a+=1
- print("DAT:",data)
- # data is now 'cleaned' - all the non-numerical values have been removed
- xinc = graph_width/(len(data)-1)
- # sets the increment on the x axis as the increment required to fit all data within the width of the graph
- if "maxi" in kwargs:
- # custom maximum value can be set if data range may not reach the highest score required for the data
- yinc = graph_height/kwargs["maxi"]
- # setting the y axis increment to fit all the data in the height set
- else:
- yinc = graph_height/max(data)
- # take the maximum value of the data as the highest value the graph should show
- values = list(data)
- # taking the values from the cleaned data
- keys = list(dataunclean.keys())
- for i in range(math.ceil((graph_height/yinc)+0.5)):
- self.create_line(45,(height-50)-yinc*i,50,(height-50)-yinc*i,width=2) # y axis incremented lines
- self.create_text(43,(height-50)-yinc*i,text=i,anchor="e") # y axis legend
- for i in range(len(keys)):
- self.create_line(50+i*xinc,height-50,50+i*xinc,height-40,width=2) # x axis incremented lines
- self.create_text(50+i*xinc,height-40,anchor="e",text=keys[i],angle=45,font=("TkDefaultFont","7")) # x axis legend
- a=0
- total = 0
- if "delay" in kwargs:
- interval = kwargs["delay"]/len(data)
- # sets the delay of graph being drawn to provided delay
- else:
- interval = 1/len(data)
- # this draws the graph in 1 second, as it is more eye-catching, and makes the user notice it has been updated
- for i in values[:-1]:
- self.create_line(50+a*xinc,(height-50)-(i*yinc),50+(a+1)*xinc,(height-50)-(values[a+1]*yinc),width=2)
- # draws a line between points of data
- a+=1
- time.sleep(interval)
- # pauses before drawing the next line
- if interval != 0:
- parent.update()
- # if graph is not updated, line is not shown until end
- # if interval is 0, there is no need to update and display lines
- total += i
- elif isinstance(dataunclean,list):
- # code below is similar to code above, but works with a list that does not provide any keys to place on y axis
- print("22222")
- print(dataunclean)
- a = 0
- data = []
- for i in dataunclean:
- if isinstance(i,int):
- data.append(dataunclean[a])
- else:
- try:
- data.append((dataunclean[a-1]+dataunclean[a+1])/2)
- except IndexError:
- data.append(dataunclean[a-1])
- except TypeError:
- data.append(dataunclean[0])
- a+=1
- print(data)
- xinc = graph_width/(len(data)-1)
- if "maxi" in kwargs:
- yinc = graph_height/kwargs["maxi"]
- else:
- yinc = graph_height/max(data)
- values = list(data)
- for i in range(math.ceil((graph_height/yinc)+0.5)):
- self.create_line(45,(height-50)-yinc*i,50,(height-50)-yinc*i,width=2) # y axis lines
- self.create_text(43,(height-50)-yinc*i,text=i,anchor="e")
- for i in range(len(data)):
- self.create_line(50+i*xinc,height-50,50+i*xinc,height-40,width=2) # x axis lines
- self.create_text(42+i*xinc,height-30,anchor="n",text=i,angle=90)
- a=0
- total = 0
- if "delay" in kwargs:
- interval = kwargs["delay"]/len(data)
- else:
- interval = 1/len(data)
- for i in values[:-1]:
- self.create_line(50+a*xinc,(height-50)-(i*yinc),50+(a+1)*xinc,(height-50)-(values[a+1]*yinc),width=2)
- a+=1
- time.sleep(interval)
- if interval != 0:
- parent.update()
- total += i
- avg = round(total/len(values),2)
- # average value is calculated
- try:
- if avg <= kwargs["goal"]:
- self.create_text(width/2,25,text="Average Score: {av}".format(av=avg),fill="red",font=("TkDefaultFont","10","bold"))
- self.create_line(50,(height-50)-(avg*yinc),50+graph_width,(height-50)-(avg*yinc),dash=(6,4),fill="red",width=5)
- # creates a label for the average score
- # if the average score is less than 3, label is turned red to draw attention to it
- elif kwargs["goal"]+(max(data)*0.1) >= avg:
- self.create_text(width/2,25,text="Average Score: {av}".format(av=avg),fill="orange",font=("TkDefaultFont","10","bold"))
- self.create_line(50,(height-50)-(avg*yinc),50+graph_width,(height-50)-(avg*yinc),dash=(6,4),fill="orange",width=5)
- else:
- self.create_text(width/2,25,text="Average Score: {av}".format(av=avg),fill="green",font=("TkDefaultFont","10","bold"))
- self.create_line(50,(height-50)-(avg*yinc),50+graph_width,(height-50)-(avg*yinc),dash=(6,4),fill="green",width=5)
- # if not more than 3, label is normal text
- except:
- self.create_text(width/2,25,text="Average Score: {av}".format(av=avg))
- self.create_line(50,(height-50)-(avg*yinc),50+graph_width,(height-50)-(avg*yinc),dash=(6,4),width=5)
- if "title" in kwargs:
- self.create_text(width/2,10,text=kwargs["title"])
- # creates title if there is a title provided
- parent.update()
- window = SquadBot()
- window.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement