Implement The Payroll Program

You designed the payroll program during week six . Now it's time to implement the program using Builder. We will add a dialog in which we want to filter the data received from the hours TEdit box to make sure we only get integers. Another new feature is the radio button which you will use to determine which type of employee you are working with.

You create the program as an SDI project , and add the menus you have designed. Next create the dialog you sketched during the design phase. We want two radio buttons one for hourly employee and the other for flat rate employee. In a group of radio buttons only one may be checked. This property of radio buttons make them ideal for choice of type of employee, since an employee can only be flat rate or hourly. Another reason for using radio buttons here rather than somthing like a combo box is that there are only a few choices. To make sure that your buttons are grouped, you first place a groupbox in the area where the radio buttons will be. Next add the radio buttons using the radio button component . Rename the buttons and finish adding edit boxes .

The Code

In your design you created a scenario for each of the menu items. The scenario for the addEmployee function contains a section for initializing the components of the Employee dialog. The radio buttons are initialized by setting the Checked property to true or false. Since only one can be true, set your default button true. If the user clicks the ok button, you want to create the correct type of employee pointer. Here again you use the Checked property to determine which type of employee to create.

 void __fastcall TSDIPayrollForm::AddEmployee1Click(TObject *Sender)
{
    EmployeeInfoDlg->Hourly->Checked = true;
    EmployeeInfoDlg->LastName->Text = "";
    EmployeeInfoDlg->FirstName->Text = "";
    EmployeeInfoDlg->Hours->Text ="";
    if (EmployeeInfoDlg->ShowModal() == IDOK)
    {
	EmployeePtr e;
	String last = EmployeeInfoDlg->LastName->Text;
	String first = EmployeeInfoDlg->FirstName->Text;
	if (EmployeeInfoDlg->Hourly->Checked)
		e = EmployeePtr(new HourlyEmployee(first,last,
				EmployeeInfoDlg->Hours->Text.ToInt()));
	else
		e = EmployeePtr(new FlatRateEmployee(first,last));
	_employees.insertItem(e);
	Invalidate();
     }
}

Filtering Data in a TEdit Box

The value returned in Hours is converted directly to an integer. This is only possible because the data retrieved from a TEdit Box was checked as it was entered to see if it was in the proper range. In some cases the data must have a certain format (such as a telephone number), then you should us a MaskEdit box (found in the additional components tab). In our dialog, the only restriction on the Hours is that the data be an integer. To ensure that only integers are entered, you can override the OnChanged event for Hours. The OnChange event occurs anytime the user enters a character into the Hours component. Each time this event occurs the last character entered will be the last character in Hours->Text. This character has subscript the corresponds to Hours->Text->Length(), since a String's subscript begins at 1. If last character is not an integer, delete it from Hours->Text and update the Hours. If the user types a character other than a number, that character will not appear in the hours box. The complete code for the hander is here.

void __fastcall TEmployeeInfoDlg::HoursChange(TObject *Sender)
{
    String s = Hours->Text;
    int len = s.Length();
    if (len>0 &&(s[len]< '0' ||
        s[len]>'9') )
    {
       s.Delete(len,1);
       Hours->Text = s;
       Hours->SelStart = len-1;
    }
}
//---------------------------------------------------------------------------

The Paint Function

In this problem you will avoid calling on Invalidate and call directly on a function called paint to refresh the list of employees on the screen. This function is similar to the print functions you saw in the grocery problem. Your main window contains a list of employees with information about each. This list must be updated in the listbox contained in the main window.

The listbox Items Text property can be directly updated by a properly constructed character array. This array is filled in by associating it with a string stream and then calling a print function similar to those used in the console problems.

void __fastcall TSDIPayrollForm::paint(TObject *Sender) 
{
    ArrayIterator< EmployeePtr> next(_employees);
    char buff[32000];
    ostrstream out(buff,32000);
    while (next)
    {
        next()->print(out);
        out << endl;
        next++;
    }
    out<<'\0';
    EmployeeList->Items->Text = buff;
}

The editEmployee Function

This function is a copy of the addEmployee function except the initialization is different, and it must delete a record before adding a new one. At design time it was decided to edit an employee selected by the user from the listbox. To implement this you first must get the subscript of the employee selected, then retrieve that employees current information to fill the components of the employee dialog. The design makes it possible for an employee to change status (i.e. move from flat rate to hourly and vice versa). If the employee changes type, you would have to delete the old pointer and add a new one. You can simplify the code by always deleting the old employee pointer and adding the new.

void __fastcall TSDIPayrollForm::EditEmployee1Click(TObject *Sender)
{
    int which = EmployeeList->ItemIndex;
    if (which >=0)
    {
        EmployeePtr e = _employees[which];
        EmployeeInfoDlg->LastName->Text = e->lastName();
        EmployeeInfoDlg->FirstName->Text = e->firstName();
        if (e->typeEmployee() == Employee::HOURLY)
        {
            EmployeeInfoDlg->Hourly->Checked = true;
            EmployeeInfoDlg->Hours->Text = e->hours();
        }
        else
            EmployeeInfoDlg->FlatRate->Checked = true;
        if (EmployeeInfoDlg->ShowModal()==IDOK)
        {
            String last = EmployeeInfoDlg->LastName->Text;
            String first = EmployeeInfoDlg->FirstName->Text;
            if (EmployeeInfoDlg->Hourly->Checked)
                e = EmployeePtr(new HourlyEmployee(first,last,
                                                   EmployeeInfoDlg->Hours->Text.ToInt()));
            else
                e = EmployeePtr(new FlatRateEmployee(first,last));
            _employees.deleteItemAt(which);
            _employees.insertItemAt(e,which);
            Invalidate();
        }
     }
}

Simple Input in Builder

Sometimes you need only have simple input of information, and don't want to create a special dialog. The function InputQuery can be used to do this. You give up the type checking by doing this. This is solely for demonstration purposes. Also note the use of MessageBox to send a message to the user.


void __fastcall TSDIPayrollForm::UpdateHours1Click(TObject *Sender)
{
    int which = EmployeeList->ItemIndex;
    if (which >=0)
    {
        String hours="";
        if (_employees[which]->typeEmployee()==Employee::HOURLY)
        {
            if (InputQuery("Employee Hours","Enter employee hours",hours)==IDOK)
            {
                _employees[which]->setHours(hours.ToInt());
                Invalidate();
            }
        }
        else
            Application->MessageBox("Cannot set hours for flat rate employee","Illegal operation",MB_OK);
    }
}

Complete Code

You can get the complete code by clicking here .