Answered step by step
Verified Expert Solution
Question
1 Approved Answer
Any help with this would be greatly appreciated! An HR Payroll System Computers are great at storing and manipulating data. For this project, you will
Any help with this would be greatly appreciated!
An HR Payroll System Computers are great at storing and manipulating data. For this project, you will write code that keeps track of Human Resources payroll data. The system will need to keep track of different types of employees for our company, and provide an easy-to-use interface for modilying the employee data. You will create a graphical user interface (GUI) using the Qt library. The best part of this library is that we can inherit from existing GUI components like tables, lists, buttons, etc. to create our own custom controls, while only need to write small amounts of code! We show how to accomplish this in the following sections. Leveraging Inheritance to Create Polymorphic Types It is not just the GUl components that will use inheritance in this project, though. We will have multiple types of employees, and while we need to hold common information for all the different types, each type may need to have custom data as well. We will be careful to create a heirarchy of code that allows us to inherit the common data, 50 as not to repeat code. Our business rules determine the types we need. Our rules for it are that it - must keep an id number, name, email address, and a path to an image for every employee. - must include a type for salaried employees that keeps track of yearly pay, and a type for hourly employees that stores the hourly wage. - must have executive and manager types that are salaried. - must have permanent and temp emplayees that are hourly. - keeps track of the hired date for permanent employees, and the last day for temp employees. UML for our design would like something like So, the bulk of our code goes in our Employee class. We can never make an instance of an Employee directly - it is marked abstract. This means that part of the code doesn't exist yet. In this case, the missing code is the calc_pay () method. This method will allow us to determine what the weekly pay is for an employee. Since some of our employees have a yearly salary and others have an hourly wage, we need the method to be written for each of them. Properties You may notice that we have not called our getters and setters names like get_ema11 and set_emai. . Instead, we are using something called properties. A property is a way that some languages allow us to create a wirtual variable; for instance consider this code: Here we created a class called Box. The job of Box is simply to hold an integer value that is between 1 and 99. In the past, you would have done this by creating a _value variable, and a get_value and a set_value methods. Something like this: This way though, has a few drawbacks. First, we don't wish to have code that validates the value passed in by the user in more than one spot. If we had copied the code from the set_value method into the constructor, but then changed aur class in some way later, we would have to modify the code in more than one spot. Repeating code is a good way to inadvertantly add bugs to our programs. So, instead of copying the code into our constructor, we have our code call the setter. It is good practice to create all of our instance variables in our constructor though, which means we need to make self._value and give it a value of None before we can call our setter. That seems a bit clunky... Additionally, with the second way of writing this class, we would need to access cur variable by calling a function each time. For instance, That's a lot of extra characters over the course of our program. If we stick with our first implementation - in which we used properties - however, we would simply use it as such: b= Box (42) print (b.value) b.value = 99 print (b.value) This is much cleaner! In addition to not needing to call getters and setters directly, we are able to simply write self.value = value in our constructor, and our setter is automatically called! We have a virtual attribute for our class now - one called value. In reality, we are still storing our data in - value ; we are simply hiding that fact from our users. Properties allow us to write less code, while also writing cleaner code. They are a win-win! Unfortunately, not all languages allow properties. Besides Python, some that do are C\#, Objective-C, JavaScript, Kotlin, and VisualBasic. Enumerations Program code can be hard to decipher and debug - even if we properly document. One way that help people reading our code to understand what we are trying to accomplish is through enumerations. Consider the following: \[ \begin{array}{l} \text { current_direction }=0 \\ \text { next_direction = } 3 \end{array} \] While the variable names seem to indicate we are storing directions, the values aren't meaningtul in that context. Enumerations allow us to give useful names to the numbers. For example: from enun inport Enum c1ass Direction (EmLn) : NORTH = 0 ERST = 1 SOdTH = 2 WaST = 3 current_d1rection = Direction.NORTH next_direction a Directon.WaST This is much more readable! Now, someone reading your code knows that you are trying to store the directions north and west in our variables. This can help them to debug our code if things aren't working properly, or to more quickly get up to speed with how our code works, In this project we will have Bole and Department enumerations. GUl Concepts We will be installing and using the PyQt library. Qt is a very fast, very robust GUi library written in C++. PyQt provides bindings for our Python code. A binding is a way for us to call code from another language in our current language. GUis with PyQt are very simple objects made with reusable and customizable components. The base class that we inherit from to create our custom components is usually a owidget. These provide all the data and methods that our object needs to be used with the Qt code. For instance, if we wanted to make a new form that simply had a label that said, "Hello there!", we could write frcm PyQt6. QtWidgets import QW1dget, QLabe1, QPushButton, oApplication, QGridLayout If we displayed this on the screen, we would get this: We could display this form by creating a Qt application, and making a new instance of our form: \# Start ot up app = oMpplication (ays.argu) \# Make a new instance of our form me = MyEorm( \# Te11 the systen to exit when ot exits. sys.exit (app-exec 0 ) Here is a more sophisticated example that has a button and changes the message presented each time the user clicks it: from PyQt6.QtWidgets 1mport QWidget, QLabe1, QPushButton, QAppilcation, garidlayout import sys Static Variables In our projects thus far, we have only had instance variables. These are variables that are owned by an instance of an abject. Sometimes they are called fields of attributes. You create one in the constructor of your object by prefacing a variable name with self. In our Bos. code above, self._value is an instance variable. Sometimes though, we wish to have a variable that all instances of the class share. These are static or class variables. We do not create one with the sele keyword. Instead, we put them before our constructors: We access static variables by using the name of the class, not the name of the object. For instance: print (Spaceship.NDM_SHIPS) We can also have getters and setters for static variables. This do not take the self parameter: det get_num_ships (l: return Spaceship.NdM_SHIPS def set_num_ships (num_ships): Spaceship.nuM_SHIFS = nun_ships Although obviously we normally want to have some checks to ensure a valid value is passed in. Datetimes Computers usually store time as the number of seconds since since some time in the past. For instance, on Unix systems it is the number of seconds since January 1, 1970 at 00:00:00 (midnight, or the beginning of that day]. For instance, "1676237282" was the time at midnight on New Years Day. Most languages provide functions to convert to more human-readable formats. Python's datetime library, for instance, lets us convert between human-readable and computer formats. To store the current time, after importing datetime, we could write importdatetinenow=datetime.date.today() If we wished to print out a human-readable version, we could write print (now. strefima ('IB 3d, WY IH: WMas') ) Similarly, if we wanted to take a string named string_date and convert it to a timestamp object, we could write A very useful feature of Python is that it will allow us to calculate new dates from old ones. So, if we wanted to set now equal to 400 days in the future, we could write now=now+datetime.timede1ta(day9u400) There are many more useful functions the datetime library provides. Read the documentation at https:ildocs.pvthon.orgl3llibrary/datetime.html for more information! Completion Steps This project is a significant endeavor and should be completed in phases. You cannot complete this in a weekend or even just the week before; be sure you start when the project is assigned and work on it a bit each day! Phase One - The Employee Types 1. Create a new project in PyCharm. 2. Add a file called employee.py . - Make an enumeration called Eole. There are three roles, CEO (number 1), CFO (number 2), and ClO (number 3 ). - Make an enumeration called Department. There are five departments in our company; from 15 they are ACCOUNTING, FINANCE, HR, R_AND_D, and MACHINING. - Add a class called InvalidRoleException. Inherit from Exception. Follow instructions from our lab on custom exceptions. - Add a class called Inva11dDepartmentexception. Inherit from Follow instructions from our lab on custom exceptions. - Make the base Employee class. Add: - 1nit_(self, name, ema11). The constructor takes the name and email string and sets the instance variables accordingly. We will be generating the 1d_number with a static variable. Static variables are owned by the class - not individual instances of a class (objects). See the section on static variables (above) for more, then create a static variable called cURkENT_ID. Set this value equal to 1. In the constructor, set the instance variable for 1d_number equal to the CURRENI_ID. At the end of the constructor, add one to CURRENT_ID so that the next employee gets a new value. Add another instance variable called IMAc_PLACEHOLDER. and set it equal to "./images/placeholdef.png". This will be the image used for the employee when no image is supplied. _str (sele]. This method should return a string with the id number, a colon, and the employee name, i.e. "1:Dr. Jane Foster". _repr__ (self). This method will be used for saving our employee to disk; it must return the name, email address, and image path separated by commas. DO NOT INCLUDE ANY OTHER DATA. We will not be storing the 1d_number in the file; instead, we will be generating that id with a static variable. - All the properties from the UML diagram. Make sure name and email strings are not blank, and that email contains the string "@acme-machining.com" (the name of our company]. Raise exceptions if violations oceur. - Add the line eron abc import ABC to the top of your file. This will import the abstract base class code. Then add eabc.abstractnethod det calc_pay(self) float: ma"This function calculates the weekly pay for the current employee for our pay report. . pass Because this method is abstract, it will need to be overriden in the children classes. - Add a class called salaried. This class will inherit from Enployee. It should have a yearly property. The yearly salary cannot be negative, and must be over $50,000. - Override ca1c_pay so that the yearly salary divided by 52.0 is returned. - Override _ reps _. Get the string from the parent __repx _ method and add to it a comma and the value for yearly before returning it. - Add a class called Hour1y. This class will inherit from Employee, It must have an hour1y property. The hourly rate must be between $15 and $99.99 (inclusive), - Override ca1c_pay so that the hourly pay multipled by 40 hours is returned. - Override to get the parent's value. Add a comma and the hourly wage and return it. - Add a class called Executive that inherits from Sa1aried. This class will hold an additional property called role. The role will be assigned as one of the three roles from the fole enumeration. If a user tries to provide a value that is not one of those values, raise an InvalidRoleException . - Override to get the parent's string, then add a comma and the value for the role to it before returning it. - Add a class called Manager that inherits from Salaried, Each Manager will have a property called department. The department will be assigned from one of the values from the Depaytment enumeration. If a user tries to provide one that is not, raise an InvaliddepartmentException . - Override _reps__ to get the parent's Add to it a comma, then the value for department before returning it. - Add a class called Fernanent. This class inherits from but has an added property for hired_date. The date must be stored as a See the section above for more info. - Override the to get the parent's string. Add to it a comma, then the value of hired_date as a string before returning it. - Add a class called Temporary, This class also inherits from , but has an added property called last_day, Override the_ to get the parent's representation, then add a comma and the value of last_day as a string, then return it. This completes the first phase. You should have your protessor or lab assistant look over your code before you begin the second phase. Phase Two - The GUI Forms The way that we created a base Employee class, then used inheritance to create specific types af employees, resulted in us having to write very little new code for each child type. We will do the same thing with the GUI - first creating an EmplopeeForm, then creating children forms by taking the existing form and customizing it. The main window of our GUI will be given to you hawever; it will result in a table of employees and looks like this: You will be able to click with your mouse on a row in this table, then by selecting "Edit current employee" from the "Edit" menu (or clicking Ctrl-E [Command-E it on a Mac]), a new window will pop-up that allows you to edit the employee information: The form that pops up will be for the particular type of employee selected; here we see an instance of an zxecutiveform. This form builds on the default Employeeform, but adds the role information, as a drop down list (a QComboBox). To write the GUI, complete the following steps 3. Read over, and make sure you understand the oode for MainWindow. This code will create a table that lists our employees. The employee data is all stored in a list called _ata. The class will make sure that changes to data will be immediately reflected in the table. Do not modify GrirableModel. 4. Complete the load file (se1f) method in Ma1nwindow. Load file will open the 'iemployee.data' file, and read the data. Code to open the file and read are given to you. You can access the file contents through the reader abject; simply write a for loop that loops over each element in the reader. Each iteration will give you a list that represents the contents of the row read. For instance, row [0] will be the employee type from the row currently being read in, and row [1] will be the employee name. From the type read in from the file, you will determine which type of Employee object to create, i.e. an Executive, Manager, Permanent, or Bourly emplayee. Note that some of the lines have an extra field, if they are a type that has a Bole or Department, After creating a now Employee of the correct sub-type, with all of the correct information set for it, add it to self. data. Once the employees are added to this list, they will show up in the table. 5. Compete the save_ I11e method in Ma1nW1ndow. Save file simply opens the ',Jemployoedata' file and loops over self._data writing the value for each object. If you coded each of your objects correctly, the repr_ (3 method will return a string of the form Manager, Fenton Crackshe11, fentoncrackshe11gacne- machining.con, ./1nages/placeholder -png, 85256.63, Accoumting. Notice this example is from a Kanager type, and has the additional DEPAETEWr information. All employee types should return a with the information in the same order, i.e. Type, Name, Email, Image Path, Pay, (Optional] Role or Department. This can be done trivially by having each sub-type call their super ( ) for the base _ repr _ 1), then adding to it. 6. Read and understand EmployeeForm. This is the base form that is used for all employee types. You will never directly instantiate an EmployeeFora. Instead, you will inherit from this class to create the custom forms you need. Notice that the I111_in method sets the data for the form by finding the Employse object at the index given by the table before it pops up. The update employee method reads the data from the GUI and stores it back in the form's - employee. 7. Create a class called Salariedform - Inherit from EmployeeForn, Override fi.11 1n to add a "Salary:" label and the pay_edit QLineEdit created in the parent form. Override update_ employee to additionally store the yearly salary entered into the current employee object. 8. Create a class called Hour1yForn, Inherit from EnployeeForm. Override f111_1n to add a "Hourly wage:" label and the _pay_edit QLineEdit created in the parent form, Override update employee to additionally store the hourly wage entered into the current employee object. 9. Create a Managerzorm that inherits from salariedzorm. Add a label with the text "Head of department:" and a oComboBox that holds each of the values from our Dopartmont enumeration. Override 1111 in to additionally set the employee's department to the one read in from the file, and override update_employee to store the selected value back in the employee object when the user clicks the update button. 10. Create an Executiveforn that inherits from Salariedforn. Add a label with the text "Role:" and a QcomboBox. that holds each of the values from our kole enumeration. Override til1_1n to additionally set the employee's role to the one read from the file, and override update_empioyee to store the selected value back in the current employee object when the user presses the update button. 11. Create a TemporaryForm that averrides the f111-in method to additionally add a label with the text "Last day;" and a label with the employee's last date as read from the file. This will be readanly, so it does not need to be a QLineEdit, and we don't need to override update enployee. . 12. Create a PermanentForm that overrides the f111-1n method to additionally add a label with the text "Hired date:" and a label with the employee's hired date as read from the file. This will be readanly, so it does not need to be a oLineEd1t, and we don't need to override update_employee. Phase Three - Error Checking Your forms must not allow the user to input bad data. If a user does enter data that is not valid, our program must adhere to the following rules: - It does nat crash - It does not update the employees with bad data - It alerts the user in some meaningful wary It is up to you to determine how you want to alert the user. You may want to make a QLineEdit that has bad data a different color, put an error message on the form, pop up an alert box, ete. It is up to you how you choose to do this, but ensure that the mechanism you choose adheres to the above ruleset. An HR Payroll System Computers are great at storing and manipulating data. For this project, you will write code that keeps track of Human Resources payroll data. The system will need to keep track of different types of employees for our company, and provide an easy-to-use interface for modilying the employee data. You will create a graphical user interface (GUI) using the Qt library. The best part of this library is that we can inherit from existing GUI components like tables, lists, buttons, etc. to create our own custom controls, while only need to write small amounts of code! We show how to accomplish this in the following sections. Leveraging Inheritance to Create Polymorphic Types It is not just the GUl components that will use inheritance in this project, though. We will have multiple types of employees, and while we need to hold common information for all the different types, each type may need to have custom data as well. We will be careful to create a heirarchy of code that allows us to inherit the common data, 50 as not to repeat code. Our business rules determine the types we need. Our rules for it are that it - must keep an id number, name, email address, and a path to an image for every employee. - must include a type for salaried employees that keeps track of yearly pay, and a type for hourly employees that stores the hourly wage. - must have executive and manager types that are salaried. - must have permanent and temp emplayees that are hourly. - keeps track of the hired date for permanent employees, and the last day for temp employees. UML for our design would like something like So, the bulk of our code goes in our Employee class. We can never make an instance of an Employee directly - it is marked abstract. This means that part of the code doesn't exist yet. In this case, the missing code is the calc_pay () method. This method will allow us to determine what the weekly pay is for an employee. Since some of our employees have a yearly salary and others have an hourly wage, we need the method to be written for each of them. Properties You may notice that we have not called our getters and setters names like get_ema11 and set_emai. . Instead, we are using something called properties. A property is a way that some languages allow us to create a wirtual variable; for instance consider this code: Here we created a class called Box. The job of Box is simply to hold an integer value that is between 1 and 99. In the past, you would have done this by creating a _value variable, and a get_value and a set_value methods. Something like this: This way though, has a few drawbacks. First, we don't wish to have code that validates the value passed in by the user in more than one spot. If we had copied the code from the set_value method into the constructor, but then changed aur class in some way later, we would have to modify the code in more than one spot. Repeating code is a good way to inadvertantly add bugs to our programs. So, instead of copying the code into our constructor, we have our code call the setter. It is good practice to create all of our instance variables in our constructor though, which means we need to make self._value and give it a value of None before we can call our setter. That seems a bit clunky... Additionally, with the second way of writing this class, we would need to access cur variable by calling a function each time. For instance, That's a lot of extra characters over the course of our program. If we stick with our first implementation - in which we used properties - however, we would simply use it as such: b= Box (42) print (b.value) b.value = 99 print (b.value) This is much cleaner! In addition to not needing to call getters and setters directly, we are able to simply write self.value = value in our constructor, and our setter is automatically called! We have a virtual attribute for our class now - one called value. In reality, we are still storing our data in - value ; we are simply hiding that fact from our users. Properties allow us to write less code, while also writing cleaner code. They are a win-win! Unfortunately, not all languages allow properties. Besides Python, some that do are C\#, Objective-C, JavaScript, Kotlin, and VisualBasic. Enumerations Program code can be hard to decipher and debug - even if we properly document. One way that help people reading our code to understand what we are trying to accomplish is through enumerations. Consider the following: \[ \begin{array}{l} \text { current_direction }=0 \\ \text { next_direction = } 3 \end{array} \] While the variable names seem to indicate we are storing directions, the values aren't meaningtul in that context. Enumerations allow us to give useful names to the numbers. For example: from enun inport Enum c1ass Direction (EmLn) : NORTH = 0 ERST = 1 SOdTH = 2 WaST = 3 current_d1rection = Direction.NORTH next_direction a Directon.WaST This is much more readable! Now, someone reading your code knows that you are trying to store the directions north and west in our variables. This can help them to debug our code if things aren't working properly, or to more quickly get up to speed with how our code works, In this project we will have Bole and Department enumerations. GUl Concepts We will be installing and using the PyQt library. Qt is a very fast, very robust GUi library written in C++. PyQt provides bindings for our Python code. A binding is a way for us to call code from another language in our current language. GUis with PyQt are very simple objects made with reusable and customizable components. The base class that we inherit from to create our custom components is usually a owidget. These provide all the data and methods that our object needs to be used with the Qt code. For instance, if we wanted to make a new form that simply had a label that said, "Hello there!", we could write frcm PyQt6. QtWidgets import QW1dget, QLabe1, QPushButton, oApplication, QGridLayout If we displayed this on the screen, we would get this: We could display this form by creating a Qt application, and making a new instance of our form: \# Start ot up app = oMpplication (ays.argu) \# Make a new instance of our form me = MyEorm( \# Te11 the systen to exit when ot exits. sys.exit (app-exec 0 ) Here is a more sophisticated example that has a button and changes the message presented each time the user clicks it: from PyQt6.QtWidgets 1mport QWidget, QLabe1, QPushButton, QAppilcation, garidlayout import sys Static Variables In our projects thus far, we have only had instance variables. These are variables that are owned by an instance of an abject. Sometimes they are called fields of attributes. You create one in the constructor of your object by prefacing a variable name with self. In our Bos. code above, self._value is an instance variable. Sometimes though, we wish to have a variable that all instances of the class share. These are static or class variables. We do not create one with the sele keyword. Instead, we put them before our constructors: We access static variables by using the name of the class, not the name of the object. For instance: print (Spaceship.NDM_SHIPS) We can also have getters and setters for static variables. This do not take the self parameter: det get_num_ships (l: return Spaceship.NdM_SHIPS def set_num_ships (num_ships): Spaceship.nuM_SHIFS = nun_ships Although obviously we normally want to have some checks to ensure a valid value is passed in. Datetimes Computers usually store time as the number of seconds since since some time in the past. For instance, on Unix systems it is the number of seconds since January 1, 1970 at 00:00:00 (midnight, or the beginning of that day]. For instance, "1676237282" was the time at midnight on New Years Day. Most languages provide functions to convert to more human-readable formats. Python's datetime library, for instance, lets us convert between human-readable and computer formats. To store the current time, after importing datetime, we could write importdatetinenow=datetime.date.today() If we wished to print out a human-readable version, we could write print (now. strefima ('IB 3d, WY IH: WMas') ) Similarly, if we wanted to take a string named string_date and convert it to a timestamp object, we could write A very useful feature of Python is that it will allow us to calculate new dates from old ones. So, if we wanted to set now equal to 400 days in the future, we could write now=now+datetime.timede1ta(day9u400) There are many more useful functions the datetime library provides. Read the documentation at https:ildocs.pvthon.orgl3llibrary/datetime.html for more information! Completion Steps This project is a significant endeavor and should be completed in phases. You cannot complete this in a weekend or even just the week before; be sure you start when the project is assigned and work on it a bit each day! Phase One - The Employee Types 1. Create a new project in PyCharm. 2. Add a file called employee.py . - Make an enumeration called Eole. There are three roles, CEO (number 1), CFO (number 2), and ClO (number 3 ). - Make an enumeration called Department. There are five departments in our company; from 15 they are ACCOUNTING, FINANCE, HR, R_AND_D, and MACHINING. - Add a class called InvalidRoleException. Inherit from Exception. Follow instructions from our lab on custom exceptions. - Add a class called Inva11dDepartmentexception. Inherit from Follow instructions from our lab on custom exceptions. - Make the base Employee class. Add: - 1nit_(self, name, ema11). The constructor takes the name and email string and sets the instance variables accordingly. We will be generating the 1d_number with a static variable. Static variables are owned by the class - not individual instances of a class (objects). See the section on static variables (above) for more, then create a static variable called cURkENT_ID. Set this value equal to 1. In the constructor, set the instance variable for 1d_number equal to the CURRENI_ID. At the end of the constructor, add one to CURRENT_ID so that the next employee gets a new value. Add another instance variable called IMAc_PLACEHOLDER. and set it equal to "./images/placeholdef.png". This will be the image used for the employee when no image is supplied. _str (sele]. This method should return a string with the id number, a colon, and the employee name, i.e. "1:Dr. Jane Foster". _repr__ (self). This method will be used for saving our employee to disk; it must return the name, email address, and image path separated by commas. DO NOT INCLUDE ANY OTHER DATA. We will not be storing the 1d_number in the file; instead, we will be generating that id with a static variable. - All the properties from the UML diagram. Make sure name and email strings are not blank, and that email contains the string "@acme-machining.com" (the name of our company]. Raise exceptions if violations oceur. - Add the line eron abc import ABC to the top of your file. This will import the abstract base class code. Then add eabc.abstractnethod det calc_pay(self) float: ma"This function calculates the weekly pay for the current employee for our pay report. . pass Because this method is abstract, it will need to be overriden in the children classes. - Add a class called salaried. This class will inherit from Enployee. It should have a yearly property. The yearly salary cannot be negative, and must be over $50,000. - Override ca1c_pay so that the yearly salary divided by 52.0 is returned. - Override _ reps _. Get the string from the parent __repx _ method and add to it a comma and the value for yearly before returning it. - Add a class called Hour1y. This class will inherit from Employee, It must have an hour1y property. The hourly rate must be between $15 and $99.99 (inclusive), - Override ca1c_pay so that the hourly pay multipled by 40 hours is returned. - Override to get the parent's value. Add a comma and the hourly wage and return it. - Add a class called Executive that inherits from Sa1aried. This class will hold an additional property called role. The role will be assigned as one of the three roles from the fole enumeration. If a user tries to provide a value that is not one of those values, raise an InvalidRoleException . - Override to get the parent's string, then add a comma and the value for the role to it before returning it. - Add a class called Manager that inherits from Salaried, Each Manager will have a property called department. The department will be assigned from one of the values from the Depaytment enumeration. If a user tries to provide one that is not, raise an InvaliddepartmentException . - Override _reps__ to get the parent's Add to it a comma, then the value for department before returning it. - Add a class called Fernanent. This class inherits from but has an added property for hired_date. The date must be stored as a See the section above for more info. - Override the to get the parent's string. Add to it a comma, then the value of hired_date as a string before returning it. - Add a class called Temporary, This class also inherits from , but has an added property called last_day, Override the_ to get the parent's representation, then add a comma and the value of last_day as a string, then return it. This completes the first phase. You should have your protessor or lab assistant look over your code before you begin the second phase. Phase Two - The GUI Forms The way that we created a base Employee class, then used inheritance to create specific types af employees, resulted in us having to write very little new code for each child type. We will do the same thing with the GUI - first creating an EmplopeeForm, then creating children forms by taking the existing form and customizing it. The main window of our GUI will be given to you hawever; it will result in a table of employees and looks like this: You will be able to click with your mouse on a row in this table, then by selecting "Edit current employee" from the "Edit" menu (or clicking Ctrl-E [Command-E it on a Mac]), a new window will pop-up that allows you to edit the employee information: The form that pops up will be for the particular type of employee selected; here we see an instance of an zxecutiveform. This form builds on the default Employeeform, but adds the role information, as a drop down list (a QComboBox). To write the GUI, complete the following steps 3. Read over, and make sure you understand the oode for MainWindow. This code will create a table that lists our employees. The employee data is all stored in a list called _ata. The class will make sure that changes to data will be immediately reflected in the table. Do not modify GrirableModel. 4. Complete the load file (se1f) method in Ma1nwindow. Load file will open the 'iemployee.data' file, and read the data. Code to open the file and read are given to you. You can access the file contents through the reader abject; simply write a for loop that loops over each element in the reader. Each iteration will give you a list that represents the contents of the row read. For instance, row [0] will be the employee type from the row currently being read in, and row [1] will be the employee name. From the type read in from the file, you will determine which type of Employee object to create, i.e. an Executive, Manager, Permanent, or Bourly emplayee. Note that some of the lines have an extra field, if they are a type that has a Bole or Department, After creating a now Employee of the correct sub-type, with all of the correct information set for it, add it to self. data. Once the employees are added to this list, they will show up in the table. 5. Compete the save_ I11e method in Ma1nW1ndow. Save file simply opens the ',Jemployoedata' file and loops over self._data writing the value for each object. If you coded each of your objects correctly, the repr_ (3 method will return a string of the form Manager, Fenton Crackshe11, fentoncrackshe11gacne- machining.con, ./1nages/placeholder -png, 85256.63, Accoumting. Notice this example is from a Kanager type, and has the additional DEPAETEWr information. All employee types should return a with the information in the same order, i.e. Type, Name, Email, Image Path, Pay, (Optional] Role or Department. This can be done trivially by having each sub-type call their super ( ) for the base _ repr _ 1), then adding to it. 6. Read and understand EmployeeForm. This is the base form that is used for all employee types. You will never directly instantiate an EmployeeFora. Instead, you will inherit from this class to create the custom forms you need. Notice that the I111_in method sets the data for the form by finding the Employse object at the index given by the table before it pops up. The update employee method reads the data from the GUI and stores it back in the form's - employee. 7. Create a class called Salariedform - Inherit from EmployeeForn, Override fi.11 1n to add a "Salary:" label and the pay_edit QLineEdit created in the parent form. Override update_ employee to additionally store the yearly salary entered into the current employee object. 8. Create a class called Hour1yForn, Inherit from EnployeeForm. Override f111_1n to add a "Hourly wage:" label and the _pay_edit QLineEdit created in the parent form, Override update employee to additionally store the hourly wage entered into the current employee object. 9. Create a Managerzorm that inherits from salariedzorm. Add a label with the text "Head of department:" and a oComboBox that holds each of the values from our Dopartmont enumeration. Override 1111 in to additionally set the employee's department to the one read in from the file, and override update_employee to store the selected value back in the employee object when the user clicks the update button. 10. Create an Executiveforn that inherits from Salariedforn. Add a label with the text "Role:" and a QcomboBox. that holds each of the values from our kole enumeration. Override til1_1n to additionally set the employee's role to the one read from the file, and override update_empioyee to store the selected value back in the current employee object when the user presses the update button. 11. Create a TemporaryForm that averrides the f111-in method to additionally add a label with the text "Last day;" and a label with the employee's last date as read from the file. This will be readanly, so it does not need to be a QLineEdit, and we don't need to override update enployee. . 12. Create a PermanentForm that overrides the f111-1n method to additionally add a label with the text "Hired date:" and a label with the employee's hired date as read from the file. This will be readanly, so it does not need to be a oLineEd1t, and we don't need to override update_employee. Phase Three - Error Checking Your forms must not allow the user to input bad data. If a user does enter data that is not valid, our program must adhere to the following rules: - It does nat crash - It does not update the employees with bad data - It alerts the user in some meaningful wary It is up to you to determine how you want to alert the user. You may want to make a QLineEdit that has bad data a different color, put an error message on the form, pop up an alert box, ete. It is up to you how you choose to do this, but ensure that the mechanism you choose adheres to the above ruleset
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started