none
How to calculate average with only one input at a time? RRS feed

  • Question

  • Hey So I'm currently making a program for employees pay. Its a wpf form using visual basic code.

    So i currently have a form that has a textbox to enter employees name and a textbox to enter employees messages sent. Then I have a label for total pay for one employee then a label for total pay for all employees and then the average for all employees.

    So my question is how do I calculate the average and total pay for the employees when I can only enter one at a time. Or is that even possiblee? I've ben stuck for a while and honestly dont know where to begin.

    I started with making a do while loop and having a variable starting at zero or whatever thats called. But I dont really understand how it works to be honest.

    Can anyone help?

    Option Strict On
    Class MainWindow
        'PieceworkWorker.vb
        '        Title: IncInc Payroll(Piecework)
        'Last Modified :   September 13 2019
        '   Written By: Deanna Slotegraaf
        'Adapted from PieceworkWorker by Kyle Chapman, September 2019
    
        'This Is a class representing individual worker objects. Each stores
        'their own name And number Of messages And the Class methods allow For
        'calculation of the worker's pay and for updating of shared summary
        'values. Name And messages are received as strings.
        'This Is being used as part of a piecework payroll application.
    
        'This Is currently incomplete; note the four comment blocks
        'below that begin With "TO DO"
    
        Public Class pieceworkworker
    
    #Region "variable declarations"
    
            ' instance variables
            Public employeename As String
            Private employeemessages As Integer
            Private employeepay As Decimal
    
            Private isvalid As Boolean = True
    
            ' shared class variables
            Private Shared overallnumberofemployees As Integer
            Private Shared overallmessages As Integer
            Private Shared overallpayroll As Decimal
    
    #End Region
    
    #Region "constructors"
    
            ''' <summary>
            ''' pieceworkworker constructor: accepts a worker's name and number of
            ''' messages, sets and calculates values as appropriate.
            ''' </summary>
            ''' <param name="namevalue">a worker's name</param>
            ''' <param name="messagesvalue">a worker's number of messages sent</param>
            Friend Sub New(ByVal namevalue As String, messagesvalue As String)
    
                ' validate and set the worker's name
                Me.name = namevalue
                ' validate and set the worker's number of messages
                Me.messages = messagesvalue
                ' calculcate the worker's pay and update all summary values
                findpay()
    
            End Sub
    
            ''' <summary>
            ''' pieceworkworker constructor: empty constructor used strictly for
            ''' inheritance and instantiation
            ''' </summary>
            Friend Sub New()
    
            End Sub
    
    #End Region
    
    #Region "class methods"
    
            ''' <summary>
            ''' currently called in the constructor, the findpay() method is
            ''' used to calculate a worker's pay using threshold values to
            ''' change how much a worker is paid per message. this also updates
            ''' all summary values.
            ''' </summary>
            ''' 
            Private Sub findpay()
    
                If (employeemessages >= 1 And employeemessages <= 2499) Then
                    employeepay = CDec(employeemessages * 0.018)
    
                End If
    
                If (employeemessages >= 2500 And employeemessages <= 4999) Then
                    employeepay = CDec(employeemessages * 0.024)
                End If
    
                If (employeemessages >= 5000 And employeemessages <= 7499) Then
                    employeepay = CDec(employeemessages * 0.03)
                End If
    
                If (employeemessages >= 7500 And employeemessages <= 10000) Then
                    employeepay = CDec(employeemessages * 0.035)
                End If
    
                If (employeemessages > 10000) Then
                    employeepay = CDec(employeemessages * 0.04)
                End If
    
    
            End Sub
    
    
    #End Region
    
    #Region "property procedures"
    
            ''' <summary>
            ''' gets and sets a worker's name
            ''' </summary>
            ''' <returns>an employee's name</returns>
            Friend Property name() As String
                Get
                    Return employeename
                End Get
                Set(namevalue As String)
                    If (String.IsNullOrEmpty(employeename)) Then
                        MessageBox.Show("error! must enter a name")
                    Else
                        findpay()
    
                    End If
    
                    employeename = namevalue
    
                End Set
            End Property
    
            ''' <summary>
            ''' gets and sets the number of messages sent by a worker
            ''' </summary>
            ''' <returns>an employee's number of messages</returns>
            Friend Property messages() As String
                Get
                    Return employeemessages.ToString()
                End Get
                Set(messagesvalue As String)
    
                    If employeemessages > 0 Then
                        findpay()
                    Else
                        MessageBox.Show("error! number must be a positive number")
                    End If
    
                    employeemessages = CInt(messagesvalue) ' this line is dangerous and should probably never appear in your code. can you explain why? post about it on the q&a board and i'll give you a stock.
    
                End Set
            End Property
    
            ''' <summary>
            ''' pay(): gets the worker's pay
            ''' </summary>
            ''' <returns>a worker's pay</returns>
            Friend ReadOnly Property pay() As Decimal
                Get
                    Return employeepay
                End Get
            End Property
            ''' <summary>
            ''' totalpay(): gets the overall total pay among all workers
            ''' </summary>
            ''' <returns>the overall total pay among all workers</returns>
            Friend Shared ReadOnly Property totalpay() As Decimal
                Get
                    Return overallpayroll
                End Get
            End Property
            ''' <summary>
            ''' gets the overall number of workers
            ''' </summary>
            ''' <returns>the overall number of workers</returns>
            Friend Shared ReadOnly Property totalworkers() As Integer
                Get
                    Return overallnumberofemployees
                End Get
            End Property
            ''' <summary>
            ''' gets the overall number of messages sent
            ''' </summary>
            ''' <returns>the overall number of messages sent</returns>
            Friend Shared ReadOnly Property totalmessages() As Integer
                Get
                    Return overallmessages
                End Get
            End Property
            ''' <summary>
            ''' calculates and returns an average pay among all workers
            ''' </summary>
            ''' <returns>the average pay among all workers</returns>
            Friend Shared ReadOnly Property averagepay() As Decimal
                Get
                    Dim messages As Integer = 0
                    Do While (messages < 10)
                        messages = messages + 1
                    Loop
    
                End Get
            End Property
    
    #End Region
    
        End Class
    
        Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
            Dim employeemessages As Integer
    
            employeemessages.findpay(lblTotalPay)
    
        End Sub
    
    End Class

    My code ^


    Saturday, September 21, 2019 4:06 PM

All replies

  • Hi

    Here is one way: this example code is a stand alone and to try, set up Form1 as shown and copy/replace all this code in Form1 code.

    The controls are as follows: Panel1 contains TextBoxes 1, 2 1nd 3 for employee1 wages, Panel2 with TextBoxes 10,11 and 12 for employee2 wages.

    TextBoxes 4 and 8n(NOT in Panels, for total wages for each employee.

    TextBox9 for average earnings for allemployees.

    This is NOT the best way to acheive desired result, but is one of many possibilities.

    ' Form1 with Panel1 containing
    ' TextBoxes 1,2,3  and Panel2
    ' containing TextBoxes 10,11,12
    ' TextBoxes 4 and 8 for emp total
    ' TextBox9 for Overall Average
    Option Strict On
    Option Explicit On
    Public Class Form1
    	Private Sub TextBox_TextChanged(sender As Object, e As EventArgs) Handles TextBox3.TextChanged, TextBox2.TextChanged, TextBox12.TextChanged, TextBox11.TextChanged, TextBox10.TextChanged, TextBox1.TextChanged
    		Dim tb As TextBox = CType(sender, TextBox)
    		Dim p As Control = tb.Parent
    
    		Select Case p.Name
    			Case "Panel1"
    				' tb1-2-3
    				TextBox4.Text = (GetDecimal(TextBox1.Text) + GetDecimal(TextBox2.Text) + GetDecimal(TextBox3.Text)).ToString("0.00")
    			Case "Panel2"
    				' tb10-11-12
    				TextBox8.Text = (GetDecimal(TextBox10.Text) + GetDecimal(TextBox11.Text) + GetDecimal(TextBox12.Text)).ToString("0.00")
    		End Select
    		TextBox9.Text = ((GetDecimal(TextBox4.Text) + GetDecimal(TextBox8.Text)) / 2).ToString("0.00")
    	End Sub
    	Function GetDecimal(s As String) As Decimal
    		Dim v As Decimal = 0
    		If Decimal.TryParse(s, v) Then Return v
    		Return -1
    	End Function
    End Class


    Regards Les, Livingston, Scotland

    Saturday, September 21, 2019 5:12 PM
  • Yeah but see this is my form so I only enter one at a time

    Saturday, September 21, 2019 5:33 PM
  • Yeah but see this is my form so I only enter one at a time

    Hi

    OK, but where is the workers pay entered?


    Regards Les, Livingston, Scotland

    Saturday, September 21, 2019 5:50 PM
  • the point of the program is to enter the messages and have the pay calculated based on numbers from this chart i have  it says that in the code
    Saturday, September 21, 2019 6:35 PM
  • Hello,

    I'm going to throw some ideas at you which may take some time to sink in. Focus not if I got what you are looking for done pat but instead a concept of using classes.

    I would recommend not performing operations current done in the window unless absolutely necessary. If you are working against many employees place them in a container such as a List of DataTable. 

    An Employee might look something similar to this (I added department identifier as if there were more than one that would be a static list or obtained from a file or database table). The overloads are custom equality (not to be concerned with presently.

    Public Class Employee
        Implements IEquatable(Of Employee)
    
        Public Property EmployeeIdentifier() As Integer
        Public Property FirstName() As String
        Public Property LastName() As String
        Public Property DepartmentIdentifier() As Integer
        Public Property Salary() As Decimal
        Public Property Messages() As Integer
        Public Overloads Function Equals(other As Employee) As Boolean Implements IEquatable(Of Employee).Equals
    
            Return other.FirstName.AreEqual(FirstName) AndAlso
                   other.LastName.AreEqual(LastName) AndAlso
                   other.DepartmentIdentifier = DepartmentIdentifier
    
        End Function
    
        Public Overrides Function GetHashCode() As Integer
    
            Return StringComparer.OrdinalIgnoreCase.GetHashCode(FirstName) Xor
                   StringComparer.OrdinalIgnoreCase.GetHashCode(LastName) Xor
                   StringComparer.OrdinalIgnoreCase.GetHashCode(DepartmentIdentifier)
    
        End Function
    
        Public Overrides Function ToString() As String
            Return $"{EmployeeIdentifier} {FirstName} {LastName} {DepartmentIdentifier}"
        End Function
    End Class

    To run through calc (which may not be exact yet you should get the idea and this is but one method) create some mocked data.

    Public Class MockedData
        Public Function EmployeeList() As List(Of Employee)
            Return New List(Of Employee) From
                {
                New Employee() With {.EmployeeIdentifier = 1, .FirstName = "Jim", .LastName = "Jones", .Messages = 10000},
                New Employee() With {.EmployeeIdentifier = 2, .FirstName = "Mary", .LastName = "Conner", .Messages = 4999},
                New Employee() With {.EmployeeIdentifier = 3, .FirstName = "Kate", .LastName = "Miller", .Messages = 7498}
                }
        End Function
    End Class
    
    

    Gain access from your window

    Dim employeeOperation = New MockedData
    Dim employeeList = employeeOperation.EmployeeList()

    Get average salary

    Dim employeeAverage = employeeList.Average(Function(emp) emp.Salary)

    Perform calculation, in this case using extension methods (AreEqual is for equality in the Employee class).

    We are interested in CalculatePay which makes uses of Between above.

    Public Module Extensions
        ''' <summary>
        ''' Perform case insensitive equal on two strings
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="item"></param>
        ''' <returns>true if both strings are a match, false if not a match</returns>
        <Runtime.CompilerServices.Extension>
        Public Function AreEqual(sender As String, item As String) As Boolean
            Return String.Equals(sender, item, StringComparison.OrdinalIgnoreCase)
        End Function
        <Runtime.CompilerServices.Extension>
        Public Function Between(Of T)(sender As IComparable(Of T), minimumValue As T, maximumValue As T) As Boolean
            Return sender.CompareTo(minimumValue) >= 0 AndAlso sender.CompareTo(maximumValue) <= 0
        End Function
        <Runtime.CompilerServices.Extension>
        Public Sub CalculatePay(sender As List(Of Employee), EmployeeIdentifier As Integer)
            Dim employee = sender.FirstOrDefault(Function(emp) emp.EmployeeIdentifier = EmployeeIdentifier)
            If employee IsNot Nothing Then
                If employee.Messages.Between(1, 2499) Then
                    employee.Salary = CDec(employee.Messages * 0.018)
                ElseIf employee.Messages.Between(2500, 4999) Then
                    employee.Salary = CDec(employee.Messages * 0.024)
                ElseIf employee.Messages.Between(5000, 7499) Then
                    employee.Salary = CDec(employee.Messages * 0.03)
                ElseIf employee.Messages.Between(7500, 10000) Then
                    employee.Salary = CDec(employee.Messages * 0.035)
                ElseIf employee.Messages > 10000 Then
                    employee.Salary = CDec(employee.Messages * 0.04)
                End If
            End If
        End Sub
    End Module

    Calculate

    Dim employeeOperation = New MockedData
    Dim employeeList = employeeOperation.EmployeeList()
    
    employeeList.CalculatePay(2)



    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Sunday, September 22, 2019 1:01 AM
    Moderator
  • Yeah but see this is my form so I only enter one at a time

    Hi

    Been away for a couple of days, had started this so will post it. I see Karen has already taken care of your issue so this post is only an extra way to tackle it.

    This is a stand alone example. If you want to try it, add the controls shown in the Designer and copy/replace all the Form1 code with this. This version saves and reloads the Employee database (tothe DeskTop - can be changed)

    There are a number of issues with the concept - such as: if the User clicks the Calculate button repeatedly then each click will repeat the add of messages for the employee (I had it clear the Messages textbox but you might want it either way). Another. Negative value for messages can be entered (can be prevented)

    Other such issues may need sorting out.

    Anyway, here it is:

    ' Form1 with TextBoxes 1-5
    ' (3, 4 and 5) readonly
    Option Strict On
    Option Explicit On
    Public Class Form1
    	Dim Employees As New Dictionary(Of String, Employee)
    
    	' where to load/save Employees data
    	Dim DataPath As String = IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.Desktop, "EmployeeData.dat")
    	Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
    		SaveEmployees()
    	End Sub
    	Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    		ReadEmployees()
    	End Sub
    	Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    		If TextBox1.Text.Length < 1 Then Exit Sub
    		' ADD
    		If Not Employees.Keys.Contains(TextBox1.Text) Then
    			If MessageBox.Show("Employee not inDataBase, do you want to ADD?", "NOT FOUND", MessageBoxButtons.YesNo) = DialogResult.Yes Then
    				' add new employee to employees
    				AddEmployee(New Employee() With {.Name = TextBox1.Text})
    				AddMesages(TextBox1.Text, GetInteger(TextBox2.Text))
    			End If
    		Else
    			AddMesages(TextBox1.Text, GetInteger(TextBox2.Text))
    		End If
    		FillFields()
    	End Sub
    	Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    		TextBox1.Clear()
    		TextBox2.Clear()
    		TextBox3.Clear()
    		TextBox4.Clear()
    		TextBox5.Clear()
    	End Sub
    	Public Sub SaveEmployees()
    		Dim fs As IO.FileStream = New IO.FileStream(DataPath, IO.FileMode.OpenOrCreate)
    		Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
    		bf.Serialize(fs, Employees)
    		fs.Close()
    	End Sub
    	Public Sub ReadEmployees()
    		If FileIO.FileSystem.FileExists(DataPath) Then
    			Employees.Clear()
    			Dim fsRead As New IO.FileStream(DataPath, IO.FileMode.Open)
    			Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
    			Employees = CType(bf.Deserialize(fsRead), Dictionary(Of String, Employee))
    			fsRead.Close()
    		End If
    	End Sub
    	Sub FillFields()
    		Dim tp As Decimal = 0@
    		If Employees.Keys.Contains(TextBox1.Text) Then
    			TextBox3.Text = GetPay(TextBox1.Text).ToString("0.00")
    		Else
    			TextBox3.Text = 0@.ToString("0.00")
    		End If
    
    		TextBox4.Text = GetTotalPayAllEmployees.ToString("0.00")
    		TextBox5.Text = GetAveragePayAllEmployees.ToString("0.00")
    	End Sub
    
    	Function GetAveragePayAllEmployees() As Decimal
    		Dim tp As Decimal = 0@
    		Try
    			tp = GetTotalPayAllEmployees() / Employees.Count
    		Catch ex As DivideByZeroException
    		End Try
    		Return tp
    	End Function
    
    	Function GetTotalPayAllEmployees() As Decimal
    		Dim tot As Decimal = 0@
    		For Each em As Employee In Employees.Values
    			tot += em.GetPay
    		Next
    		Return tot
    	End Function
    	Function GetMessages(name As String) As List(Of Integer)
    		Return Employees(name).AllMessages
    	End Function
    	Function GetPay(name As String) As Decimal
    		Return Employees(name).GetPay()
    	End Function
    	Sub RemoveMessages(name As String, messages As Integer)
    		Employees(name).RemoveMessages(messages)
    	End Sub
    	Sub AddMesages(name As String, messages As Integer)
    		Employees(name).AddMessages(messages)
    	End Sub
    	Sub AddEmployee(em As Employee)
    		Try
    			Employees.Add(em.Name, em)
    		Catch ex As ArgumentException
    			If ex.Message.Contains("already been added") Then
    				MessageBox.Show("ERROR: " & em.Name & vbCrLf & ex.Message & vbCrLf & "NOT ADDED")
    			End If
    		End Try
    	End Sub
    	Function GetDecimal(s As String) As Decimal
    		Dim v As Decimal = 0@
    		If Decimal.TryParse(s, v) Then Return v
    		Return -1@
    	End Function
    	Function GetInteger(s As String) As Integer
    		Dim v As Integer = 0
    		If Integer.TryParse(s, v) Then Return v
    		Return 0
    	End Function
    
    	' ===============================
    	<Serializable> Class Employee
    		Property Name As String
    		Property Messages As New List(Of Integer)
    
    		Function GetPay() As Decimal
    			Dim tm As Decimal = Messages.Sum
    			Select Case tm
    				Case < 2500
    					Return tm * 0.018@
    				Case < 5000
    					Return tm * 0.024@
    				Case < 7500
    					Return tm * 0.03@
    				Case < 10000
    					Return tm * 0.035@
    				Case Else
    					Return tm * 0.04@
    			End Select
    		End Function
    		Function AllMessages() As List(Of Integer)
    			Return Messages
    		End Function
    		Sub AddMessages(amount As Integer)
    			Messages.Add(amount)
    		End Sub
    		Sub RemoveMessages(amount As Integer)
    			Messages.Add(-amount)
    		End Sub
    	End Class
    End Class


    Regards Les, Livingston, Scotland


    • Edited by leshay Sunday, September 22, 2019 4:51 PM
    Sunday, September 22, 2019 4:49 PM