C# Tutorial - A Simple Calculator – Simple Functionality


By virtue of the visual design, we can determine most of the functionality required.

  • We need to be able to store two values to be manipulated.
  • We need to store the operation to be performed on the two values.
  • We need to be able to store a value for memory.
  • We also need to be able to clear the screen.
  • Perform the specified operation when the equals button is pressed.

The first thing to do here is to declare some attributes within the class Form1:

private double _num1, _num2;
private string _prevOP; // previous operation
private bool _clrDisplay;

private double _memory;

Each of these values need initialising in the constructor.

_num1 = 0.0;
_num2 = 0.0;
_clrDisplay = true;
_prevOP = "";
_memory = 0.0;
Result.Text = "";

Now we can start adding event for the button's Click events.

Cancel Button

The cancel (C) button simply wants to clear what is currently being displayed within the Result label. So double-click on buttonC to create the default Click event and add the following code:

Result.Text = "";

Cancel Everything Button

The Cancel Everything (CE) button needs to clear what is currently being displayed within the Result label, clear both of the values to be manipulated and clear the operation to be performed on the two values. So double-click on buttonCE to create the default Click event and add the following code:

_num1 = 0.0;
_num2 = 0.0;
_prevOP = "";
Result.Text = "";

Numeric Buttons

The ten numeric buttons could have individual Click event handlers which have very similar code within them, or they could all use the same Click event handler. The latter choice makes more sense. Add the following code to Form1.cs.

private void Numeric_Click(object sender, EventArgs e)
{
  Result.Text = Result.Text + ((Button)sender).Text;
}

Now wire the event to the numeric buttons using these steps.

  1. Highlight all ten buttons by holding down the control button on the keyboard and selecting each one.

  2. Click on the lightning bolt button at the top of the Properties Window to open the events pane.

  3. Click in the right hand column of the Click event, and click on the down arrow that appears. Choose the method that we just defined.

All ten buttons should now have the same event handler. You can check this by building the application and running it. Click on some of the buttons and numbers should appear in the Result label.

Decimal Point Button

The decimal point button can be handled in one of two ways. Either give the button its own handler, or tie it into the Numeric_Click event handler as per the other numeric buttons. The latter method allows all of the numeric functionality to be kept together.

Add the Numeric_Click event handler to the decimal point button as per the same instructions as the numeric buttons above. Check this works by building the application and running it. Click on the decimal point button several times. The application has no intelligence built into it at the moment, so for every time you click on the decimal point button, another decimal point is added to the text in the Result label.

We can overcome this problem by adding some intelligence to the Numeric_Click event handler. Change the code so it now looks like the following:

private void Numeric_Click(object sender, EventArgs e)
{
  // Check to see if the decimal point has been pressed
  if (((Button)sender).Text == ".")
  {
    // Check to see if a decimal point already exists.
    if ((Result.Text.IndexOf(".", 0) >= 0))
    {
      // If it does, change the value of the buttons text
      // to an empty string.
      ((Button)sender).Text = "";
    }
  }

  // Add the text to the Result label
  Result.Text = Result.Text + ((Button)sender).Text;
}

The problem is solved in such that only one decimal point will appear in the Result label, however when you press the button for a second time, the decimal points disappears off the button. This can be solved by using a local copy of the button that has been pressed. Change the code so it now looks like the following:

private void Numeric_Click(object sender, EventArgs e)
{
  // Take a copy of the button that has been pressed
  Button bt = (Button)sender;

  // Check to see if the decimal point has been pressed
  if (bt.Text == ".")
  {
    // Check to see if a decimal point already exists.
    if ((Result.Text.IndexOf(".", 0) >= 0))
    {
      // If it does, change the value of the buttons text
      // to an empty string.
      bt.Text = "";
    }
  }

  // Add the text to the Result label
  Result.Text = Result.Text + bt.Text;
}

Now when you build and run the application, the text does not disappear off the button.

Addition, Subtraction, Division and Multiplication Buttons

Each of these buttons allows a simple operation to be performed on two numeric values. Using the same approach as the numeric buttons, we can create a single method to handle the events for all of the buttons. The method needs to store the current value and the operation that has been pressed, so that when we implement the equals button, we can store the second value and display the result. The method also needs to clear the Result label.

Add the following code to Form1.cs.

private void SimpleOp_Click(object sender, EventArgs e)
{
  // Store first value
  _num1 = double.Parse(Result.Text);

  // Store operation
  _prevOP = ((Button)sender).Text;

  // Clear the Result label.
  _clrDisplay = true;
}

Now wire the event to the operation buttons using these steps.

  1. Highlight all four buttons by holding down the control button on the keyboard and selecting each one.

  2. Click on the lightning bolt button at the top of the Properties Window to open the events pane.

  3. Click in the right hand column of the Click event, and click on the down arrow that appears. Choose the method that we just defined.

By setting the boolean _clrDisplay to true, the Numeric_Click method needs altering to accommodate this:

private void Numeric_Click(object sender, EventArgs e)
{
  // Take a copy of the button that has been pressed
  Button bt = (Button)sender;

  // Check to see if the display needs clearing.
  if (_clrDisplay == true)
  {
    Result.Text = "";
    _clrDisplay = false;
  }

  // Check to see if the decimal point has been pressed
  if (bt.Text == ".")
  {
    // Check to see if a decimal point already exists.
    if ((Result.Text.IndexOf(".", 0) >= 0))
    {
      // If it does, change the value of the buttons text
      // to an empty string.
      bt.Text = "";
    }
  }

  // Add the text to the Result label
  Result.Text = Result.Text + bt.Text;
}

Now when you build and run the application, the Result label clears on the next numeric key press after a simple operation has been performed.

An exception can occur if any of the operation buttons are pressed with the Result label being empty. So to cater for this we can catch the exception and return from the handler without doing anything.

private void SimpleOp_Click(object sender, EventArgs e)
{
  try
  {
    // Store first value
    _num1 = double.Parse(Result.Text);

    // Store operation
    _prevOP = ((Button)sender).Text;

    // Clear the Result label.
    _clrDisplay = true;
  }
  catch
  {
    // FormatException will occur if Result label is empty
  }
}

Equals Button

The equals button needs to store the current value and perform the operation upon it and the stored first value that was previously selected. So double-click on buttonEquals to create the default Click event and add the following code:

private void buttonEquals_Click(object sender, EventArgs e)
{
  try
  {
    // Store second value
    _num2 = double.Parse(Result.Text);

    // local variable to hold the result of the operation
    double result = 0.0;

    // Perform the operation based on the
    // operation that was stored previously
    switch (_prevOP)
    {
      case "+":
        result = _num1 + _num2;
        break;

      case "-":
        result = _num1 - _num2;
        break;

      case "x":
        result = _num1 * _num2;
        break;

      case "/":
        result = _num1 / _num2;
        break;
    }

    // Display the result
    Result.Text = result.ToString();

    // Clear the operation
    _prevOP = "";

    // Clear the Result label.
    _clrDisplay = true;
  }
  catch
  {
    // FormatException will occur if Result label is empty
  }      
}

<< Previous Contents Next >>

© Publicjoe, 2008