In my Teacher Gradebook application, I'm creating a class called Student. The class will record all of a student's information like
Code:
Public Class Student
Private pFirstName As String = ""
Private pLastName As String = ""
Private pMinimumDGrade As Integer = 60
Private pMinimumCGrade As Integer = 70
Private pMinimumBGrade As Integer = 80
Private pMinimumAGrade As Integer = 90
Private pBookNumber As String
'Address stuff
Private pAddress As String
Private pCity As String
Private pState As String = "OK"
Private pZipCode As String
Private pHomePhoneNumber As String
Private pCellPhoneNumber As String
Private pEmailAddress As String
'Parent Info - Mother
Private pMotherFirstName As String
Private pMotherLastName As String
Private pMotherHomePhoneNumber As String
Private pMotherWorkPhoneNumber As String
Private pMotherCellPhoneNumber As String
Private pMotherEmailAddress As String
'Parent Info - Father
Private pFatherFirstName As String
Private pFatherLastName As String
Private pFatherHomePhoneNumber As String
Private pFatherWorkPhoneNumber As String
Private pFatherCellPhoneNumber As String
Private pFatherEmailAddress As String
Private pHomeworkAverage As String = "=="
Private pTestAverage As String = "=="
Private pQuizAverage As String = "=="
Private pLabAverage As String = "=="
Private pNineWeeksAverage As String = "=="
Private pFinalNineWeeksAverage As String = "=="
Private pSemesterAverage As String = "=="
Private pFinalSemesterAverage As String = "=="
End Class
I have no problems with properties that hold only one value. Here's the problem.
For each student, I need to also keep a list of Grades on assignments. This needs to be a two dimensional array. Something like this.
Why dont you make a class for it and give each student a list of the class...
Code:
Class Grade
Private Paper as string 'ID of paper/exam/class/course etc
Private Score as double
End Class
in the student class, put this
Code:
Private grds as new list(of Grade)
private function calc_avg() as double
dim i as double
for each g as grade in grds
i += g.score
next
return (i / grds.items.count)
end function
Also you should declare the minimum grades as shared constants, as I guess they wont change.
And create a class for personal info, and have 2 instances of it within the student class, one called mother and one called father...
Code:
Public Class DemographicInfo 'personal/address ****
private phone as string 'etc
'''
'''
End Class
Also, if a student has more than one paper/class you might want to consider creating a class of course (I would use class, but thats a keyword), and have the grades list in that and a few properties, maybe teacher, class_name etc...
Last edited by cptHotkeys; Jul 2nd, 2007 at 05:09 PM.
I'd have to agree with that approach. In general, if you ever think you need a multi-dimensional array, consider whether or not a one dimensional array of classes could be used instead. There are several advantages to doing it that way:
1) List (of Type) This is a MUCH nicer list than a simple array. Most of the functionality you want is built in.
2) You can implement the IComparable interface so that you can do custom sorting on whatever piece of the class you want.
3) Sizing, copying, manipulating, a 1D array is much nicer and intuitive than a multi-D array.
4) When you have classes, you can do various things with properties to allow access to the class. This may not be much of an advantage, but you might find some useful ways to store data and retrieve data. Offhand, I can't think of any example in this case that wouldn't be fairly silly, but maybe you can.
2) You can implement the IComparable interface so that you can do custom sorting on whatever piece of the class you want.
Would you mind giving some example of this, I know how to implement the interface into a class and handle what ever I need to in there, but what do you do after that?
what args are passed and returned to and from the subs and functions?
The thing is dead simple. You add the Implements IComparable interface and get the stub of the CompareTo sub, which you fill out roughly as I have in the example, adding whatever specific comparisons you want. Also, as I noted, this comes right from the MSDN example, so if you want a further example, you can go there, but it will look just like the one I have, as I only changed the types.
Guys, this is my first attempt at programming in VB 2005. I wrote this gradebook program in VB6 originally and had no problem setting up arrays for my StudentInfo TYPE. Types were easy to understand. I'm having trouble getting my head around setting up array structures inside a class within VB2005.
Sorry if my questions seem, um..., basic. I'm trying.
Questions for cptHotkeys...
make a class for IT
What do you mean by IT?
declare the minimum grades as shared constants, as I guess they wont change"
Do you mean the number of grades for that student, or a number of grades for all students, of the minimum score for a certain paper or what? What will be the purpose of doing that?
Your code for finding the average, while mathematically correct, will not work in my case. Each paper is worth a variable number of points. One point for each problem. I don't use percent scores except when I figure averages. How should I handle this?
I think if I can ever get one good example figured out, I can apply it to the others.
Public Const MaxGradeCount = 60
Public Const MaxStudentCount = 35
Public Const MaxAttendanceCount = 50
Public Const GradeColumnWidth = 420
Public Type AttendanceInfo
DateAT() As Date
Kind() As String * 2
End Type
Public Type ClassInfoType
FileName As String
ClassName As String * 30
GradeCount(1 To 4) As Integer
AttendanceCount(1 To 4) As Integer
HomeworkPct(1 To 4) As Integer
TestPct(1 To 4) As Integer
QuizPct(1 To 4) As Integer
LabPct(1 To 4) As Integer
OtherPct(1 To 4) As Integer
NineWeeksTestPct(1 To 4) As Integer
SemesterTestPct(1 To 4) As Integer
StudentCount As Integer
End Type
Public Type AssignmentInfoType
AssignmentDescription As String * 30
KindOfGrade As String * 13
DateAssigned As String
DateTurnedIn As String
TimesCounted As Integer
PerfectScore As Integer
End Type
Public Type StudentInfoType
FirstName As String * 14
LastName As String * 14
DMinimum As Integer 'for students on special grading scale
CMinimum As Integer
BMinimum As Integer
AMinimum As Integer
BookNumber As String * 4 'string in case it has a letter like 22a and 22b
Address As String * 20
City As String * 12
State As String * 2
ZipCode As String * 7
PhoneNumber As String * 12
Email As String
MotherName As String * 30 'parent names & numbers
MotherPhoneNumber As String * 12
FatherName As String * 30
FatherPhoneNumber As String * 12
Grade() As String * 4 'list of grades for each assignment
Attendance() As String * 2 ' list of attendance values
'Each student's various averages -- either a number or "==" if no average
HomeworkAvg(1 To 4) As String * 3
TestAvg(1 To 4) As String * 3
QuizAvg(1 To 4) As String * 3
LabAvg(1 To 4) As String * 3
OtherAvg(1 To 4) As String * 3
NineWeeksAvg(1 To 4) As String * 3
NineWeeksTest(1 To 4) As String * 3
FinalNineWeeksAvg(1 To 4) As String * 3
SemesterTest(1 To 2) As String * 3
SemesterAvg(1 To 2) As String * 4
FinalSemesterAvg(1 To 2) As String * 4
End Type
Well, all of those types could be recreated into classes or structures with the same members declared public, and altered in some standard ways (like the arrays need to be zero based).
1) I would take your parental information and make a class that contains that, then have the student class have two instances of the parental information class, one for mother and one for father.
2) The minimumXgrade seems like it would be constant, but you suggest that it will not actually remain constant for all students or all time, so I guess it shouldn't be declared as constant, but that's really minor.
3) pBookNumber seems like it ought to be a number not a string. Is there a reason for it being a string? Use a number when you can, because strings are relatively slow.
4) For the same reason, the averages shouldn't be strings. There is no real advantage to having a number contained in a string, because you can get a string from a number using the .ToString method (and you should ALWAYS have Option Strict On, just in case you don't). Keeping a number as a string means that you have to do the slow parsing back to a number when you need it as a number.
5) None of those averages should be there (which makes point #4 pretty silly). The class should hold the data. Those averages should be properties that return the correct value based on the raw data which will be maintained in the classes I mention in #6.
6) It sounds like you need to keep track of A) what the grade was; B) What time period it occured in (don't understand the Nine Week thing, but you do); C) What the weighting of that value is for calculating averages. These three items define a class:
vb Code:
Public Class Grade
Private mValue as Integer 'No fractional grades allowed
Private mWeight as decimal
Private mTimePeriod as Integer 'Actually, I have NO idea what type this should be
Public Sub New (val as integer ,weight as decimal,TimePeriod as Something)
mValue=val
mWeight = weight
mTimePeriod = TimePeriod
End Sub
Public ReadOnly Property GetScore() as double
Get
return mValue*mWeight
End Get
End Property
'Other Properties for the time period, the true value, and perhaps a property
'To alter the weight.
'Maybe a method to make a copy of this class.
End Class
Something like that would be a start. You would have a List (Of Grade) member in the student class, and a method like AddGrade() that would take the three arguments needed to create a new instance of the Grade class, then create a new instance, and add it to the List.
To get the average for a period would have lots to do with what that third member of the Grade class is. You would iterate through the list checking to see whether or not that grade is part of the period you want to get an average for, and adding in the GetValue as needed while incrementing a counter. The average would be exposed via a ReadOnly property that did that iterating, adding, and dividing, and returned the actual average. I would also suggest that the average be returned as a Decimal, though I return the GetScore as a double. Do the math as a double, then cast the result to a decimal. Not sure if this is necessarily a good idea, but I prefer using Decimals.
Oh yeah, I see you have Quizz average, lab average, etc., so I think it would be good to add a new field to the Grade class called mType, which would tell what Type the grade is. This would allow creating averages for those categories of grades.
1. I get the idea for parental instances of contact info.
2. MinimumXGrade has to be set for each student. Some students have Individual Education Programs. I'm required by federal law to follow this IEP. IEP's might include things like a modified grading scale. So normally, 60% is a D. But for some students, only 50% is required to make a D. This is used after figuring the final averages and assigning letter grades.
3. Yeah, the books are usually numbered. But sometimes a lost # 4 gets returned after I've already replaced is. So one of them has to become #4a or something like that.
4. I make all the grades and averages string because they will not always be numbers. For example, I usually exempt the lowest test grade at the end of 9 weeks. To do this, a low grade of 32 might get changed to 32x. Then when figuring averages, any grade that contains "x" is exempt, ignored. Sometimes, students are absent and I just exempt a grade by giving it a value of "x". Same thing if they turn in late papers. I don't want to give them a zero if they do the work, but at the same time, many of them just copy the graded papers that I've already returned to students who were present. Giving them an "x" avoids the zero but gives them no credit for copying. Turning in nothing would be figured in as a zero.
5. I included averages in the type only to make displaying averages in the GUI easier and to make printing reports easier. It's way easier to say
Code:
Printer.Print Student.SemesterAverage
than to have to go figure the average and then print it.
6.The 9 weeks thing...
All the high schools that I know of around here divide the school year into 4 quarters. In each quarter, there are usually 9 weeks of school. I suppose we could call them quarters but we don't. Two quarters (or 18 weeks) makes up one semester. Two semesters makes a complete school year. We figure averages at each of these intervals.
I do appreciate you taking the time to help. I think I'm leaning more and more toward just keeping the information that I need in a set of 4 grids, one for each quarter. It's very easy to add a new grade or student to the end of the data and inserting a new grade or student in the middle is quick too. With only 20 or so students in each class/course, and only about 50 grades in each quarter, I don't think the program will bog down too much when figuring averages.
I can keep all the info like AssignmentDate, TurnInDate, GradeType, PossiblePerfectScore, and such in a hidden DataGridView rather than bothering with arrays. If I insert a new column in the grid containing grades, I just insert a column in the hidden grid to match it.
I'm going to give this a try for now...
But I'm still looking into classes as well.
3) An alternative would be to use a decimal system 4.1 instead of 4a, which would allow you to use a Decimal type instead of a string. Makes little difference in that case, though.
4) That's just an internal representation of a grade. Using a negative number or something would work just as well as an X, but it would keep the type numeric, and would work better for the logic, but see #5 below.
5) That's not actually easier at all. What I am suggesting would be to do no more than that, but the average would be calculated on the fly. The class would do the work, the property would return the value. You have to do the work anyways, so why not calculate it on the fly? You can name the property whatever you want such that you could have the exact same line that you posted, except that it would calculate the new average as needed which would remove any question as to whether or not any changes in the grades had been reflected in the averages. As long as you code in the average as a member variable you have to keep careful track as to whether or not the average reflects the current state of the data. By using a well crafted property, that issue goes away because the average is always based on the current state of the information in the class.
6) I'd stay away from the DataGridView. That's nothing but a complex multi-D array anyways, with a fair amount of overhead. By not showing it you improve performance considerably, but it is still misuse of the concept. A control is there specifically for user interactions. Data constructs like arrays are there for organizing data.
Still, whatever works is what is most important. There may be better ways to do pretty much anything, but if those better ways do not fall within our sphere of understanding, then they may not be better for us.
4. But what happens when a new student moves in in the middle of the year? My students already have 20 grades and the new student is exempt from all of them, making his average 0 out of 0. What I've done before is to show a "==" for situations like this. At the top of my program, I display the HomeworkAverage, TestAverage, QuizAverage, LabAverage, (4 or each) QuarterAverage, and SemesterAverage (2 of each) in labels. The labels are filled in based on which row I'm on in the grid (like a revved up spreadsheet).
5.Every time I change rows in my grid (spreadsheet), the labels at the top of the program (displaying the student's average) are updated. Wouldn't this slow down the program a lot if it has to figure all of those averages each time there's a row change in the grid? In my VB6 version of this, the averages were already figured and stored in the array. The only time averages had to be figured was when the file was first loaded, when a cell in the grid was changed (a grade was entered or changed), if a new student was added, if a new grade/assignment was added, or if the AssignmentInfo (type or perfect possible score) was changed.
I like the idea of being able to just "get" Student(i).SemesterAverage but I think it would put a lot of strain on the CPU.
6. I will HAVE to use a DataGridView to show the student names and grades. This is a spreadsheet king of application. Test grades are shown in red, quizzes in blue, homework is black, etc. Student names will be different colors based on their averages. You don't want your name in red or blue.
You would never notice that trivial strain on the CPU. For one genetic algorithm I have, I have to run a whole dataset through a set of 100 polynomial equations, plus do a whole lot of other stuff, and I get an iteration time of about 3 iterations per second on a fairly average computer. You would be doing FAR less calculations for each row, so you would take so little time that you would never even see it happen.
As for the first issue, that's a real one. My first instinct would be to set all non-recorded grades to -1 (which is not the same as 0, of course). This would give you enough information to decide what to do with a grade when calculating the average. As to how you would display the result.....I would think that if the returned value was -1, you could then put "==" into the label rather than Value.ToString (or whatever you call the -1 number). You would have the advantages of using numbers (which are faster than strings for absolutely everything, and are value types, to boot), and you would only need to interpret them for display.
6) When you get right down to it, this whole thing looks like it makes a lot more sense as a database. That would make working with a datagrid make more sense, as well. You'd have a table of students with studentIDs which would be the foreign key for a table of grades, and a table of parents.
Of course, then you are getting into a different realm, but it would have the advantage of being naturally persistent data.
I've been working a little more with the Class idea (rather than just the grid control) but I'm still having a hard time getting arrays set up within the class.
I just don't understand how to use the Get and Set for a property that uses an array.
I tried this...
vb Code:
Public Class GradeCount
Private pGradeCount As Integer
Public Property GradeCount()
Get
Return pGradeCount
End Get
Set(ByVal value)
pGradeCount = value
End Set
End Property
End Class
Public Class CourseInfo
Private pCourseName As String = "New Course"
Private pTeacher As String = ""
'Student info
Private pGradeCount(0 To 4) As List(Of GradeCount)
Private pStudentCount As Integer = 0
Private pCurrentQuarter As Integer = 1
Private pCurrentWeek As Integer = 1
Private pAttendenceCount(0 To 4) As Integer
'Percents
Private pTestPercent As Integer = 50
Private pHomeworkPercent As Integer = 50
Private pQuarterTestPercent As Integer = 20
Private pSemesterTestPercent As Integer = 20
'File info
Private pFileVersion As String
Private pFileName As String
Private pWasEdited As Boolean = False
Private pWasSaved As Boolean = False
Public Property CourseName()
Get
Return pCourseName
End Get
Set(ByVal value)
pCourseName = value
End Set
End Property
Public Property FileVersion()
Get
Return pFileVersion
End Get
Set(ByVal value)
pFileVersion = value
End Set
End Property
Public Property Teacher()
Get
Return pTeacher
End Get
Set(ByVal value)
pTeacher = value
End Set
End Property
Public Property GradeCount(ByVal Index As Integer)
Get
Return pGradeCount(Index)
End Get
Set(ByVal value)
pGradeCount(Index) = value
End Set
End Property
End Class
But when I try to put a number into one of the "GradeCounts", I get the error
Code:
Unable to cast object of type 'System.Int16" to type 'System.Collections.Generic.List' 1[FlexGrade4._1.GradeCount]'.
It says...
Code:
When casing from a number, the value must be a number less than infinity.
Ok, cool. But which number is not less than infinity?
What should I change.
Oh by the way, I think I should make one big class called Course that will keep up with everything. It will keep the CourseName, TeacherName, a list of StudentNames, a list of StudentGrades, StudentAverages, etc.
Then I could do something like...
Course.GradeCount(1) for the number of grades in the first quarter (first 9 weeks)
Course.Student(3).SemesterAverage(2) would give me the 2nd semester average for student number 3.
Anyway, the code below does as I expected until I get to the Inputs that wants GradeCount.
For example: (Use Lists instead of arrays as they will simplify this allot)
If you had a grade list inside a class and you wanted to add an item to that, you do this (it wont fit right into your code but you should get the idea of when to use a property and when not, when refering to lists and arrays)
Code:
Public sub AddGrade(Byval s as string)
gradeList.add(s)
End Sub
Public Function RemoveGrade(byval strText as string) as boolean
dim i as integer
for each s as string in gradeList
if s = strText then
gradeList.removeat(i)
return true
end if
i += 1
next
return false
End sub
If you wanted to "SET" the list of grades or "GET" the list of grades then you would use a property, dont perform functional actions on a property like adding an item to a list or removing an item, things like that should be public subs, or functions if there is a possibility that the function wont fullfill a task that returns boolean values and when a object is needed to be returned for processing or decision making...
Code:
Public Property Grades () as list(of string)
Get() as list(of String)
return gradeList
End Get
Set(Byval value as list(of string)
gradeList = value
End Set
End property
I tried it but I still couldn't get it to work. I think I'm getting dumber so I'm going to simplify this down to one specific thing in my class. If I can just get this one thing right, I can probably fix all the others.
In my class, called CourseInfo, I want to be able to access the GradeCount() property. I need GradeCount() to be an array, or a List, or a collection, or whatever the crap it's called in this language and it has to be able to hold 4 different values - though I suppose they way you're setting things up, I could keep adding as many as I want (not just 4).
I think I understand the concept of adding and removing GradeCount's just like you would add rows or columns to the DataGridView. What I don't understand is how I set that up in my class. And in my program, I need there to already be 4 (or 5 if it has to be zero-indexed) GradeCounts available. I don't want to have to add them at runtime programmatically. Is that possible?
What do I need to do to this code to make it work right?
vb Code:
Public Class GradeCount
Private pGradeCount As Integer
Public Property GradeCount()
Get
Return pGradeCount
End Get
Set(ByVal value)
pGradeCount = value
End Set
End Property
End Class
Public Class CourseInfo
Private pGradeCount As List(Of GradeCount)
Public Property GradeCount() As List(Of Integer)
Get() as list(of integer)
Return GradeCountList
End Get
Set(ByVal value As List(Of Integer))
GradeCountList = value
End Set
End Property
Public Function RemoveGradeCount(ByVal s As Integer) As Boolean
email me your source code and i will fix it and comment it with full detailed descriptions of what, how and why I have done what i will for you if you want?
In my further studying, I came up with the code below which does what I'm trying to do and is very familiar to me. Just about the same thing as VB6. Not sure if I can create a function (like for figuring a student's average when a grade changes) but I'm sure there are simple ways around that.
vb Code:
Public Class Form1
Public Structure CourseType
Public Name As String
Public Teacher As String
Public StudentCount As Integer
Public GradeCount() As Integer
Public WeekOfSchool As Integer
End Structure
Public Course As New CourseType
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Course.Name = "My Course Name"
Course.Teacher = "Mr. Teacher"
Course.StudentCount = 25
ReDim Course.GradeCount(5)
Course.GradeCount(1) = 10
Course.GradeCount(2) = 20
Course.GradeCount(3) = 30
Course.GradeCount(4) = 40
With Course
Dim m As String
m = .Name & vbCrLf
m = m & .Teacher & vbCrLf
m = m & Str(.StudentCount) & "students" & vbCrLf
m = m & Str(.GradeCount(1)) & " grades in 1st Quarter" & vbCrLf
m = m & Str(.GradeCount(2)) & " grades in 2nd Quarter" & vbCrLf
m = m & Str(.GradeCount(3)) & " grades in 3rd Quarter" & vbCrLf
m = m & Str(.GradeCount(4)) & " grades in 4th Quarter" & vbCrLf
MessageBox.Show(m)
End With
End Sub
End Class
So why bother with classes at all?
MSDN suggests using a structure (rather than a class) when you have a small amount of data with which to work. I'll only have about 35 students in a classroom - and that would be a REALLY big class at my school. I'll set a maximum of about 70 grades for each quarter. I only assign about 50 pages per quarter and I known as the teacher who assigns the most work.
Of course, I'm still interested in how classes compare to structures so I'd love to see the code you're preparing for me. Just wanted to get someones opinion on what I just said.
Last edited by DroopyPawn; Jul 5th, 2007 at 12:14 AM.
Well, I've figured out how to make a one dimensional array work in a custom class. I could get a grade count for each quarter in the school year using the code below.
vb Code:
Public Class CourseInfo
Public GradeCount() as Integer = {0,0,0,0,0}
End Class
I still can't get a two dimensional array to work.
And then I just set or get the GradeCount I want with in the main program with ...
I got the 2-dimensional thing working but I guess I'm not really using the List idea.
vb Code:
Public Const MaxStudentCount = 50
Public Const MaxGradeCount = 50
Public Class StudentInfo
Public FirstName As String = ""
Public LastName As String = ""
Public Score(0 To 4, 0 To MaxGradeCount) As String
Private Sub InitializeScores()
Dim q As Integer, g As Integer
For q = 0 To 4
For g = 0 To 50
Score(q, g) = ""
Next g
Next q
End Sub
Sub New()
Dim Quarter As Integer
Dim Grade As Integer
For Quarter = 0 To 4
For Grade = 0 To 50
Score(Quarter, Grade) = 0
Next
Next
End Sub
End Class
Public Class CourseClass
Public Name As String = "New Class"
Public Student(0 To 30) As StudentInfo
Sub New()
Dim NewStudent As New StudentInfo
Dim i As Integer
For i = 0 To 30
Student(i) = NewStudent
Next
End Sub
End Class
Dim Course As New CourseClass
Private Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
Dim i As Integer = 5
MessageBox.Show(Course.Student(13).Score(3, 5))
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Course.Name = "Algebra"
Course.Student(1).FirstName = "Abby"
Course.Student(1).LastName = "Apple"
Course.Student(2).FirstName = "Ben"
Course.Student(2).LastName = "Bobble"
Course.Student(1).Score(1, 1) = 100
Course.Student(1).Score(3, 5) = 53
Course.Student(13) = Course.Student(1)
End Sub
Just paiste the code above into a form and run it. Clicking on the form gives the MessageBox
My code still doesn't use any kind of FindAverage function to create a property for averages. By the way, I'll be dropping the Quiz, Lab, and Other grade types. Everything will now be Test, Homework, QuarterTest or SemesterTest. Only Test and Homework will need to be averaged.
Now after reading SEVERAL MDSN topics on classes, structures, and anything I could find that might be relevant, I have a better idea of what you were suggesting. I'm liking your ideas more and more. I still just can't quite get it done though.
Could you do me a favor? Create all of the code for me to handle just the student names and grades. I'll add all the other stuff I need from your example. I'll give you a text file that contains all the student names and grades - sort of like what my program's text files will look like.
I really appreciate all the effort you've put into this so far. Here's a text file for you.
Each line in the text file is....
Line 1. The Class/Course Name
Line 2. The GradeCount for each Quarter (53 grades in the 1st quarter, 35 grades in the 4th quarter).
Line 3-6. The HomeWorkPercent and TestPercent for each Quarter.
Line 7. Percentages for QuarterTest and SemesterTest
Line 8. The number of students.
Line 9. A student's name (Leandra Dushane)
Line 10. Leandra's grades for the 1st Quarter
Line 11. Leandra's grades for the 2nd Quarter
Line 12. Leandra's grades for the 3rd Quarter
Line 13. Leandra's grades for the 4th Quarter
Lines 14-23 Two more students, Flower and Brian.
In the rest of the file, each line is the information for one grade.
"Workbook 1-1 ","Homework ","08,11,2006","08,11,2006", 1, 25
AssignmentDescription "Workbook 1-1"
KindOfGrade "Homework"
AssignedDate "08,11,2006"
DueDate "08,11,2006"
Weight = 1 (it's counted one time)
PerfectScore = 25