sixstorm
June 26th, 2013, 01:51 PM
Hello everyone. I am a CIT instructor at a technical college and have come up with a small C++ app to clock students in and out (some have coop jobs and it's hard to keep track of 20-40 students). The app I created (C++ version) earlier this year has worked out quite well, but some other instructors wanted to implement this in their class. I decided to rewrite the app in Python and use the Tkinter GUI to make it a lot easier than the previous version: all text/CLI based.
Most of the app is ready to go and the basic functionality is there. There are just a few things I need another set of eyes on, thus why I'm posting here.
Disclaimer: This is my first Python app (more than the basic stuff) so don't judge me. I've basically pieced tutorials together since that's how I learn programming the best.
This app is extremely simple: there are two listboxes(available students and present students) with Clock In, Clock Out and Exit buttons. Students come in, find their name in the AStudents listbox, select it and click on the Clock in Button. Done. If they have to leave early, they can find their name in the PStudents listbox, select it and click on the Clock out Button. All of these actions get written out into a log file (log file is named after the MM/DD/YYYY format), then another Python script emails it to the instructor.
I do have future plans on adding more things such as passwords for each student, an admin console, etc. But other instructors need this going by the end of the week, bugs or not.
1) I have built in a "resume" feature to where if a student accidentally exits/closes the program, the instructor can just click on a resume menu item and all is well. When I try this out on the app, it will look at 'resume.txt', input the first name in the text file into the PStudent listbox, but give the error "TclError: bad listbox index "Cecil Huffines": must be active, anchor, end, @x,y, or a number" Is it because it wants to refer to the item number in the listbox(0, 1, 2, etc)? Not sure what's up with that or how I could get around it.
Maybe there is another way to accomplish a resume feature that I haven't thought of?
2) As I mentioned, a log file with each students name and clock in/out time is created when the buttons are pressed. I would like these logs to look a bit better by actually showing how many hours and minutes that they have been present. For example, our school hours are from 8-2:30, and each student is here for 6 hours a day (take out lunch and breaks) for our attendance records. I would like the logs to say:
John Doe Clocked in at 8:00 Clocked out at 1:00 Present for 4.5 hours
Each time that I try to look up information on how to calculate time, it's always a simple app where you have to put in the times manually. Hopefully you can see where I'm going with this.
3) If a student has not clocked in and they accidentally press the Clock Out button, it needs to show a proper error message of what they did. As of the code below, doing this action will do nothing, but console throws out an error message stating that the "tuple index out of range". Any way to correct this?
I think that's all I have right now. This app is decently solid as it stands but needs some dummy proofing. My eyes can't take any more code at the moment, thus I needed some opinions and advice. TIA!
from Tkinter import *
from sets import Set
import tkMessageBox
import tkFileDialog
import datetime
now = datetime.datetime.now()
filename1 = datetime.datetime.now().strftime("%m%d%Y") + '.txt'
presentStudents = list([])
absentStudents = list([])
verNum = "1.3"
resumeBefore = False
clockedIn = False
class App:
def __init__(self, master):
self._master = master
frame1 = Frame(master)
frame2 = Frame(master)
frame1.grid(row=0, column=0)
frame2.grid(row=0, column=1)
self.value = None
#Define the scrollbars
stuScrollbar1 = Scrollbar(frame1)
stuScrollbar2 = Scrollbar(frame1)
self.aStuLabel = Label(frame1, text="Available Students")
self.aStuLabel.grid(row=0, column=0)
self.pStuLabel = Label(frame1, text="Present Students")
self.pStuLabel.grid(row=0, column=2)
#Define the All Student ListBox and set the scrollbar to the right
self.aStuLB = Listbox(frame1, selectmode=SINGLE, yscrollcommand=stuScrollbar1.set)
stuScrollbar1.config(command=self.aStuLB.yview)
stuScrollbar1.grid(row=1, column=1, sticky='NS')
self.aStuLB.grid(row=1, column=0)
#Define the Present Student ListBox and set the scrollbar to the right
self.pStuLB = Listbox(frame1, selectmode=SINGLE, yscrollcommand=stuScrollbar2.set)
stuScrollbar2.config(command=self.pStuLB.yview)
stuScrollbar2.grid(row=1, column=3, sticky='NS')
self.pStuLB.grid(row=1, column=2)
#Define the clock in button
ciButton = Button(frame2, text="Clock In", command=self.clockIn)
ciButton.grid(row=0, column=0)
#Define the clock out button
coButton = Button(frame2, text="Clock Out", command=self.clockOut)
coButton.grid(row=1, column=0)
#Define the exit button
exitButton = Button(frame2, text="Exit", command=frame1.quit)
exitButton.grid(row=2, column=0)
#Define the menubar and options
menubar = Menu(self._master)
helpMenu = Menu(menubar, tearoff=0)
helpMenu.add_command(label="Resume from Crash", command=self.resume)
helpMenu.add_command(label="About", command=self.showAboutBox)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label="Open Student File", command=self.file_open)
filemenu.add_command(label="Exit", command=frame1.quit)
menubar.add_cascade(label="File", menu=filemenu)
menubar.add_cascade(label="Help", menu=helpMenu)
self._master.config(menu=menubar)
# Automatically populates the listbox from 'students.txt', and adds all students to the 'absentStudents' list
filename = open("students.txt")
for line in filename:
line = line.rstrip('\n')
self.aStuLB.insert(END,line)
absentStudents.append(line)
print absentStudents
#Opens a file using the open file dialog box
def file_open(self):
filename = tkFileDialog.askopenfilename()
with open(filename,'r') as f:
for line in f:
self.aStuLB.insert(END,line)
#Function for clocking in
def clockIn(self):
now = datetime.datetime.now()
self.value = self.aStuLB.curselection()[0]
stuName = self.aStuLB.get(self.value)
print stuName
if stuName in absentStudents:
#Add student to presentStudents list, move student from Total Student ListBox to Present Student ListBox, and pop up information box
try:
presentStudents.append(stuName)
absentStudents.remove(stuName)
self.pStuLB.insert(END,stuName)
self.aStuLB.delete(self.value)
except:
print "Error: Cannot move student"
#Write to log file and to resume backup file
try:
f = open(filename1, 'a')
f.write(stuName + "\n" + "Clock In at " + now.strftime("%a - %m-%d-%y %H:%M") + "\n")
f.close()
except:
tkMessageBox.showinfo("Error", "Can't write to log")
pass
try:
f = open('resume.txt', 'a')
f.write(stuName + "\n")
f.close()
except:
print "Cannot write to resume log!"
pass
elif stuName in presentStudents:
tkMessageBox.showinfo("Error", "You must clock in first!")
else:
tkMessageBox.showinfo("Error", "General Error")
#Show Clock In Message
tkMessageBox.showinfo("Clocked In", "You have clocked in at " + now.strftime("%H:%M"))
#Function for clocking out
def clockOut(self):
now = datetime.datetime.now()
self.value = self.pStuLB.curselection()[0]
stuName = self.pStuLB.get(self.pStuLB.curselection()[0])
if stuName in presentStudents:
#Write to log file
try:
f = open(filename1, 'a')
f.write(stuName + "\n" + "Clock Out at " + now.strftime("%a - %m-%d-%y %H:%M") + "\n")
f.close()
except:
tkMessageBox.showinfo("Error", "Can't write to log")
pass
#Remove student from presentStudents list, move student from Present Student ListBox to Total Student ListBox, and pop up information box
try:
presentStudents.remove(self.pStuLB.get(self.value) )
for item in presentStudents:
print item
self.aStuLB.insert(0,self.pStuLB.get(self.value))
self.pStuLB.delete(self.value)
except:
print "Error: Cannot move student"
tkMessageBox.showinfo("Clocked Out", "You have clocked out at " + now.strftime("%H:%M"))
else:
tkMessageBox.showinfo("Error", "You have not clocked in yet!")
pass
def showAboutBox(self):
#Show the About Dialog Box w/Information
top2 = Toplevel()
top2.title("About TCAT Timeclock")
Label(top2, text="TCAT Timeclock App v" + verNum).pack()
aboutOkButton = Button(top2, text="OK", command=top2.destroy).pack()
def resume(self):
#Resume from accidental close out or crash
print resumeBefore
if resumeBefore == True:
tkMessageBox.showinfo("You have already resumed your last session.")
pass
#resumeBefore = True
filename = open("resume.txt")
#Read in names from 'resume.txt' into presentStudents list, then remove them from absentStudents list
for line in filename:
line = line.rstrip('\n')
presentStudents.insert(0, line)
print "Present Students: \n"
print presentStudents
print "\n"
#absentStudents.remove(line)
print "Absent Students: \n"
print absentStudents
self.pStuLB.insert(END,line)
self.aStuLB.delete(line)
#Insert presentStudents into pStuLB
for line in presentStudents:
self.pStuLB.insert(END,line)
root = Tk()
root.title("TCAT Timeclock v" + verNum)
# Definition to center window when launching
def center_window(w=300, h=200):
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
app = App(root)
center_window(475, 275)
root.mainloop()
Most of the app is ready to go and the basic functionality is there. There are just a few things I need another set of eyes on, thus why I'm posting here.
Disclaimer: This is my first Python app (more than the basic stuff) so don't judge me. I've basically pieced tutorials together since that's how I learn programming the best.
This app is extremely simple: there are two listboxes(available students and present students) with Clock In, Clock Out and Exit buttons. Students come in, find their name in the AStudents listbox, select it and click on the Clock in Button. Done. If they have to leave early, they can find their name in the PStudents listbox, select it and click on the Clock out Button. All of these actions get written out into a log file (log file is named after the MM/DD/YYYY format), then another Python script emails it to the instructor.
I do have future plans on adding more things such as passwords for each student, an admin console, etc. But other instructors need this going by the end of the week, bugs or not.
1) I have built in a "resume" feature to where if a student accidentally exits/closes the program, the instructor can just click on a resume menu item and all is well. When I try this out on the app, it will look at 'resume.txt', input the first name in the text file into the PStudent listbox, but give the error "TclError: bad listbox index "Cecil Huffines": must be active, anchor, end, @x,y, or a number" Is it because it wants to refer to the item number in the listbox(0, 1, 2, etc)? Not sure what's up with that or how I could get around it.
Maybe there is another way to accomplish a resume feature that I haven't thought of?
2) As I mentioned, a log file with each students name and clock in/out time is created when the buttons are pressed. I would like these logs to look a bit better by actually showing how many hours and minutes that they have been present. For example, our school hours are from 8-2:30, and each student is here for 6 hours a day (take out lunch and breaks) for our attendance records. I would like the logs to say:
John Doe Clocked in at 8:00 Clocked out at 1:00 Present for 4.5 hours
Each time that I try to look up information on how to calculate time, it's always a simple app where you have to put in the times manually. Hopefully you can see where I'm going with this.
3) If a student has not clocked in and they accidentally press the Clock Out button, it needs to show a proper error message of what they did. As of the code below, doing this action will do nothing, but console throws out an error message stating that the "tuple index out of range". Any way to correct this?
I think that's all I have right now. This app is decently solid as it stands but needs some dummy proofing. My eyes can't take any more code at the moment, thus I needed some opinions and advice. TIA!
from Tkinter import *
from sets import Set
import tkMessageBox
import tkFileDialog
import datetime
now = datetime.datetime.now()
filename1 = datetime.datetime.now().strftime("%m%d%Y") + '.txt'
presentStudents = list([])
absentStudents = list([])
verNum = "1.3"
resumeBefore = False
clockedIn = False
class App:
def __init__(self, master):
self._master = master
frame1 = Frame(master)
frame2 = Frame(master)
frame1.grid(row=0, column=0)
frame2.grid(row=0, column=1)
self.value = None
#Define the scrollbars
stuScrollbar1 = Scrollbar(frame1)
stuScrollbar2 = Scrollbar(frame1)
self.aStuLabel = Label(frame1, text="Available Students")
self.aStuLabel.grid(row=0, column=0)
self.pStuLabel = Label(frame1, text="Present Students")
self.pStuLabel.grid(row=0, column=2)
#Define the All Student ListBox and set the scrollbar to the right
self.aStuLB = Listbox(frame1, selectmode=SINGLE, yscrollcommand=stuScrollbar1.set)
stuScrollbar1.config(command=self.aStuLB.yview)
stuScrollbar1.grid(row=1, column=1, sticky='NS')
self.aStuLB.grid(row=1, column=0)
#Define the Present Student ListBox and set the scrollbar to the right
self.pStuLB = Listbox(frame1, selectmode=SINGLE, yscrollcommand=stuScrollbar2.set)
stuScrollbar2.config(command=self.pStuLB.yview)
stuScrollbar2.grid(row=1, column=3, sticky='NS')
self.pStuLB.grid(row=1, column=2)
#Define the clock in button
ciButton = Button(frame2, text="Clock In", command=self.clockIn)
ciButton.grid(row=0, column=0)
#Define the clock out button
coButton = Button(frame2, text="Clock Out", command=self.clockOut)
coButton.grid(row=1, column=0)
#Define the exit button
exitButton = Button(frame2, text="Exit", command=frame1.quit)
exitButton.grid(row=2, column=0)
#Define the menubar and options
menubar = Menu(self._master)
helpMenu = Menu(menubar, tearoff=0)
helpMenu.add_command(label="Resume from Crash", command=self.resume)
helpMenu.add_command(label="About", command=self.showAboutBox)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label="Open Student File", command=self.file_open)
filemenu.add_command(label="Exit", command=frame1.quit)
menubar.add_cascade(label="File", menu=filemenu)
menubar.add_cascade(label="Help", menu=helpMenu)
self._master.config(menu=menubar)
# Automatically populates the listbox from 'students.txt', and adds all students to the 'absentStudents' list
filename = open("students.txt")
for line in filename:
line = line.rstrip('\n')
self.aStuLB.insert(END,line)
absentStudents.append(line)
print absentStudents
#Opens a file using the open file dialog box
def file_open(self):
filename = tkFileDialog.askopenfilename()
with open(filename,'r') as f:
for line in f:
self.aStuLB.insert(END,line)
#Function for clocking in
def clockIn(self):
now = datetime.datetime.now()
self.value = self.aStuLB.curselection()[0]
stuName = self.aStuLB.get(self.value)
print stuName
if stuName in absentStudents:
#Add student to presentStudents list, move student from Total Student ListBox to Present Student ListBox, and pop up information box
try:
presentStudents.append(stuName)
absentStudents.remove(stuName)
self.pStuLB.insert(END,stuName)
self.aStuLB.delete(self.value)
except:
print "Error: Cannot move student"
#Write to log file and to resume backup file
try:
f = open(filename1, 'a')
f.write(stuName + "\n" + "Clock In at " + now.strftime("%a - %m-%d-%y %H:%M") + "\n")
f.close()
except:
tkMessageBox.showinfo("Error", "Can't write to log")
pass
try:
f = open('resume.txt', 'a')
f.write(stuName + "\n")
f.close()
except:
print "Cannot write to resume log!"
pass
elif stuName in presentStudents:
tkMessageBox.showinfo("Error", "You must clock in first!")
else:
tkMessageBox.showinfo("Error", "General Error")
#Show Clock In Message
tkMessageBox.showinfo("Clocked In", "You have clocked in at " + now.strftime("%H:%M"))
#Function for clocking out
def clockOut(self):
now = datetime.datetime.now()
self.value = self.pStuLB.curselection()[0]
stuName = self.pStuLB.get(self.pStuLB.curselection()[0])
if stuName in presentStudents:
#Write to log file
try:
f = open(filename1, 'a')
f.write(stuName + "\n" + "Clock Out at " + now.strftime("%a - %m-%d-%y %H:%M") + "\n")
f.close()
except:
tkMessageBox.showinfo("Error", "Can't write to log")
pass
#Remove student from presentStudents list, move student from Present Student ListBox to Total Student ListBox, and pop up information box
try:
presentStudents.remove(self.pStuLB.get(self.value) )
for item in presentStudents:
print item
self.aStuLB.insert(0,self.pStuLB.get(self.value))
self.pStuLB.delete(self.value)
except:
print "Error: Cannot move student"
tkMessageBox.showinfo("Clocked Out", "You have clocked out at " + now.strftime("%H:%M"))
else:
tkMessageBox.showinfo("Error", "You have not clocked in yet!")
pass
def showAboutBox(self):
#Show the About Dialog Box w/Information
top2 = Toplevel()
top2.title("About TCAT Timeclock")
Label(top2, text="TCAT Timeclock App v" + verNum).pack()
aboutOkButton = Button(top2, text="OK", command=top2.destroy).pack()
def resume(self):
#Resume from accidental close out or crash
print resumeBefore
if resumeBefore == True:
tkMessageBox.showinfo("You have already resumed your last session.")
pass
#resumeBefore = True
filename = open("resume.txt")
#Read in names from 'resume.txt' into presentStudents list, then remove them from absentStudents list
for line in filename:
line = line.rstrip('\n')
presentStudents.insert(0, line)
print "Present Students: \n"
print presentStudents
print "\n"
#absentStudents.remove(line)
print "Absent Students: \n"
print absentStudents
self.pStuLB.insert(END,line)
self.aStuLB.delete(line)
#Insert presentStudents into pStuLB
for line in presentStudents:
self.pStuLB.insert(END,line)
root = Tk()
root.title("TCAT Timeclock v" + verNum)
# Definition to center window when launching
def center_window(w=300, h=200):
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
app = App(root)
center_window(475, 275)
root.mainloop()