Object_Oriented_Programming in C#
Exercise: Building a calculator
The exercise will be presented as a mini use case describing what the fictive customer want
you to implement and leave you to figure it out, it is described this way to model a miniature
real world scenario.
The use case
The customer is adamant that no hardcoded values should exist in the event methods and
that such values should be declared as constants at the beginning of the Form1 class to
make the code more maintainable. Any class level variables should also be declared at the
beginning of the class.
The calculator only need to calculate a result using two values. When entering values using
the numbered buttons the current value should be displayed with large digits in the value
label. When one of the arithmetic buttons (+, -, x, /) is clicked the value should be moved
and displayed with a much smaller font in a label displayed over a small portion of the
value label (see image below).
The delete (←), clear (C), memory (M) and memory recall (MR) buttons should be placed
below the value label as well as a label (blue background) which should display used the
arithmetic character (+, -, x, /) when one of the buttons is clicked.
The delete (←) button should remove the last entered digit (the right most digit). Note that
you have to make sure that the minus sign is replaced with a 0 if the last numerical digit of
a negative value is deleted. You also have to add a 0 to the large value label if the last
numeri- cal digit of a positive value is deleted.
The clear (C) button should clear the value in all the small value label and the label
displaying the arithmetic character and assign 0 to the large value label.
The memory (M) button should store the value in the large value label in a string variable
called memory for later use.
The memory recall (MR) button should recall the value in stored in the memory variable and
display the value in the large value label.
The number buttons should append the digit to the end of the value in the large value label.
The same goes for the decimal character which only should be allowed once in the large value
label.
When one of the arithmetic buttons is clicked the value in the large value label should be
moved to the small value label and the arithmetic symbol should be displayed in the blue label
to the right of the memory recall button. This symbol will then be used to determine how the
result should be calculated when the button with the equal sign on it is clicked. These buttons
should be handled by the same event method called btnCalculate_Click.
When the square root (√) button is clicked the square root of the value in the large value label
should be calculated using the Sqrt method in the Math class and the result displayed in the
large value label replacing the original value. You should also handle negative values because
it is not possible to calculate the square root of a negative value, display a message box with
a suitable message.
The negation button (±) should act as a toggle button adding and removing a minus sign (-) to
the left of the value in the large value label.
When the calculate button (=) is clicked the result should be calculated using the values from
the small and large value labels as well as the symbol store in the blue label.
The number buttons should use the same event method called btnNumber_Click. You can
cast the sender parameter (from the event parenthesis) to a button using the Button class and
use the variable you store the clicked button in to access its Text property.
Button btn = (Button)sender;
Rules regarding calculating the result
If one of the labels contain an empty string or if the large value label contain 0 no calculation
should take place and the event should be prematurely ended using the return keyword.
if (...) return;
If the last character in either of the two value labels is a decimal sign then that character
should be removed prior to the calculation being performed.
The calculation performed should be determined by the arithmetic sign is displayed in the
blue label.
After the calculation the blue label and the small value label should be cleared by assigning
an empty string to their Text properties.
The result should be displayed in the large value label with three (3) decimal digits. You
can use the format functionality of the ToString method to achieve this. Also if the value
is calculated as for instance 10.0 where the value ends with a zero decimal value (,0 or .0)
then the zero and the decimal symbol should be removed from the string using the
Replace method before the value is displayed in the large value label.
lblValue.Text = result.ToString("F3").Replace(zeroDecimal, String.Empty);
Now structure the information given to you in a document before you start
implementing the solution. For instance what constants could be used in place of hard
coded text and val- ues. I suggest that you implement the solution in incremental stages
to see that one functionality works before proceeding with something new.
The solution
I hope you have tried to implement the solution before deciding to resort to the solution
presented here. You will start by creating the GUI and move on from there to implement
the button logic culminating in the actual calculation when hitting the button with the
equal sign.
The value labels
1. Create a new Windows Forms Application solution called Simple Calculator.
2. Resize the form to 314px wide and 383px high.
3. Drag a label to the form which represent the value that the user enters through
clicking on the numerical buttons.
4. Rename the label lblValue.
5. Set the AutoSize property to false to be able to resize the label.
6. Change the background color to white and the border style to Fixed3D to make it
look more like a textbox.
7. Change the font to Consolas 20pt to make the text larger.
8. Resize the label to 274px wide and 46px high.
9. Assign the value 0 to the Text property.
10. Align the text to the bottom right with the TextAlign property.
11. Next drag another label to the form and rename it lblFirstValue.
12. Set the AutoSize property to false to be able to resize the label.
13. Change the background color to white and the border style to None to remove any
border around the label.
14. Change the font to Consolas 10pt to make the text smaller.
15. Resize the label to 270px wide and 14px high.
16. Clear the Text property by deleting any value in it.
17. Align the text to the middle right with the TextAlign property.
18. Reposition the label on top of the first label so that it appears that it is part of the
upper section of the label.
The buttons
All buttons have the same size except the 0 which has double the width of the other buttons
and the equals button which has double the height of the other buttons. The buttons are 50px
wide and 50px high. The special characters for the delete (←), square root (√) and negation
(±) buttons can be copied from a word processor's Insert Symbol functionality and pasted into
the Text property of the button or you can use the Unicode value for the desired symbol if the
value is added programmatically in the form's Load event (←, \u2190), (√,
\u221A) and (±, \u00B1).
btnSign.Text = "\u00B1";
The math function label (the blue one)
The purpose of this label is to show the user which mathematical function has been chosen
when clicking on one of the (+, -, /, x) buttons. The value stored in this label will then be used
to determine how the result will be calculated; you could off course use a variable to store
this information but then it would not be visible to the user.
1. Add a label to the form and change its name to lblMathFunction.
2. Resize the label to the same height (50px) and width (50px) as the buttons.
3. Reposition the label to the right of the Memory Recall (MR) button.
4. Change the background color to blue.
5. Change the text color to White with the ForeColor property.
6. Change the text alignment to MiddleCenter with the TextAlign property.
7. Change the Font to Consolas 20pt.
8. Change the border style to FixedSingle.
The numerical buttons
Name the numerical buttons btnOne, btnTwo and so on.
To avoid a lot of duplicated code and to make it more compact and maintainable you
should create one Click event that is used by all numerical buttons. To access the
clicked button's Text property (or any other property) you can cast the sender
parameter to a Button, the sender parameter is sent in through the event's
parenthesis.
You have to take into consideration that the value label which contain the current value
entered so far could contain the default 0 assigned when the calculator is started or
when the value is cleared using either the delete or clear button. If this is the case then
you first have to clear the label by assigning an empty string to it before adding the
button's value to the Text property of the label.
One way of appending the correct numerical value at the end of the value in the value
label is to use the text from the button itself because it holds the necessary number.
You can fetch the value from the Text property of the variable you cast earlier.
1. Select one of the numerical buttons and enter btnNumber_Click in its Click event field
in the Properties window and then press Enter on the keyboard. This should create
the event method and take you to it.
private void btnNumber_Click(object sender, EventArgs e)
{
}
2. Add a variable called btn which will hold the cast sender parameter and cast the
sender parameter to a Button to be able to use its properties.
Button btn = (Button)sender;
3. Because the customer wanted all constant values to be stored as constants you will
add a constant named noValue to the form's class just inside its opening curly brace
and assign the value 0 to the constant.
public partial class Form1 : Form
{
const string noValue = "0";
4. Use the constant you just added in an if-statement checking if the lblValue label is
equal to that value, if it is then clear the label by assigning an empty string to it. Note
that you don't have to use curly braces to add a block to an if-statement that only
executes one line of code.
if (lblValue.Text == noValue)
lblValue.Text = String.Empty;
5. The last thing you have to do is to append the numerical value of the button to the
end of the text in the lblValue label, you can do this by using the += operator.
lblValue.Text += btn.Text;
6. Now that the event method has been implemented you should add it to the Click
event of all other numerical buttons using the Events section of the Properties win-
dow.
7. Run the application and make sure that the number corresponding to the button you
click is appended to the end of the text in the lblValue label (the large label).
8. Close the application.
Here's the complete code for the event used with the numerical buttons Click events:
private void btnNumber_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
if (lblValue.Text == noValue)
lblValue.Text = String.Empty;
lblValue.Text += btn.Text;
}
The Delete button
The purpose of the Delete button is to remove the rightmost character from the lblValue
label when clicked. There are a couple of edge cases you must take into consideration here:
• You should remove the last digit of the label value only if it contain more than one
character otherwise the label value should be reset to 0 using the noValue constant
you created earlier.
• If the label contain only one digit and it is a minus sign the value of the label should
be reset to 0 using the noValue constant you created earlier.
1. Name the button btnDelete.
2. Double click on the Delete (←) button to add its Click event method to the code-
behind file.
3. Declare a string variable called newValue and assign the default value store in the
noValue constant. The variable will hold the new value as it is created throughout the
event.
string newValue = noValue;
4. Next fetch the length of the text stored in the lblValue label and store it in an int
variable called length. You will need this value to determine if the first edge case
should be applied or if the last digit should be removed from the value.
int length = Convert.ToInt32(lblValue.Text.Length);
5. Use the length variable to determine if the last digit should be removed and if so
remove it using the Substring method of the label's Text property storing the result in
the newValue variable you created earlier.
if (length > 1)
newValue = lblValue.Text.Substring(0, length - 1);
6. Check if the remaining value in the newValue is equal to a minus sign denoting that a
negative number was used, if it is reset the value of the variable to the value stored
in the noValue constant. Store the minus character in a string constant named
minusSign at the beginning of the form and use it instead of hard coding the minus
sign in the if-statement.
if (newValue.Equals(minusSign))
newValue = noValue;
7. Assign the value in the newValue variable to the Text property of the lblValue label.
8. Run the application and make sure that the Delete button works properly.
9. Close the application.
Here's the complete code for the Delete button:
private void btnDelete_Click(object sender, EventArgs e)
{
string newValue = noValue;
int length = Convert.ToInt32(lblValue.Text.Length);
if (length > 1)
newValue = lblValue.Text.Substring(0, length - 1);
if (newValue.Equals(minusSign))
newValue = noValue;
lblValue.Text = newValue;
}
The Clear button
The purpose of the Clear button is to clear the labels and assign default values to them.
1. Name the button btnClear.
2. Double click on the Clear button in the form to create its Click event.
3. Assign the value of the noValue constant to the lblValue label to reset its value to 0.
4. Assign an empty string to the lblFirstValue and lblMathFunction labels to clear
them.
5. Run the application and make sure that the clear button works properly.
6. Close the application.
Here's the complete code for the Clear button:
private void btnClear_Click(object sender, EventArgs e)
{
lblValue.Text = noValue;
lblFirstValue.Text = String.Empty;
lblMathFunction.Text = String.Empty;
}
The Memory button
The purpose of the Memory (M) button is to store the current value from the label lblValue
in a form level string variable called memory. The user should then be able to recall that value
by clicking on the Memory Recall (MR) button.
1. Name the button btnMemory.
2. Double click on the Memory button in the form to create its Click event.
3. Scroll to the beginning of the form and create a new string variable called memory
below the already existing constants and assign an empty string to it.
string memory = String.Empty;
4. Scroll back to the btnMemory_Click event.
5. Assign the text in the lblValue label to the memory variable.
6. Reset the value of the lblValue label to the value stored in the noValue constant.
Here's the complete code for the Memory button:
private void btnMemory_Click(object sender, EventArgs e)
{
memory = lblValue.Text;
lblValue.Text = noValue;
}
The Memory Recall button
The purpose of the Memory Recall (MR) button is to recall the value stored in the memory
variable and assign that value to the lblValue label.
1. Name the button btnMemoryRecall.
2. Double click on the Memory Recall button in the form to create its Click event.
3. Assign the value from the memory variable you created at form level in the previous
section to the lblValue label.
4. Run the application to test the Memory and Memory Recall buttons by entering a
value using the numerical buttons and then clicking on the Memory button. Clear the
label by clicking on the Clear button and then click on the Memory Recall button to
fetch the value in the memory variable and display it in the lblValue label.
5. Close the application.
Here's the complete code for the Memory Recall button:
private void btnMemoryRecall_Click(object sender, EventArgs e)
{
lblValue.Text = memory;
}