In the last couple of posts we have spent a bunch of time separating the GUI from the logic. Let complete this shift and get everything wired back up into a working program in this Noob to Pro post about how to integrate the GUI.
How to Integrate the GUI
Lets look and see where we are in our code. Just to catch everyone up.
FormCalc
using System; using System.Windows.Forms; using System.Collections.Generic; namespace NoobToPro { public partial class FormCalc : Form { List<Number> values; const string ONE = "1"; const string TWO = "2"; const string THREE = "3"; const string FOUR = "4"; const string FIVE = "5"; const string SIX = "6"; const string SEVEN = "7"; const string EIGHT = "8"; const string NINE = "9"; const string ZERO = "0"; const string PERIOD = "."; const string ADD = "+"; const string SUBTRACT = "-"; const string DIVIDE = "/"; const string MULTIPLE = "*"; const string EQUALS = "="; public FormCalc() { InitializeComponent(); } private void btn7_Click(object sender, EventArgs e) { txtInput.Text += SEVEN; } private void btn8_Click(object sender, EventArgs e) { txtInput.Text += EIGHT; } private void btn9_Click(object sender, EventArgs e) { txtInput.Text += NINE; } private void btn4_Click(object sender, EventArgs e) { txtInput.Text += FOUR; } private void btn5_Click(object sender, EventArgs e) { txtInput.Text += FIVE; } private void btn6_Click(object sender, EventArgs e) { txtInput.Text += SIX; } private void btn1_Click(object sender, EventArgs e) { txtInput.Text += ONE; } private void btn2_Click(object sender, EventArgs e) { txtInput.Text += TWO; } private void btn3_Click(object sender, EventArgs e) { txtInput.Text += THREE; } private void btn0_Click(object sender, EventArgs e) { txtInput.Text += ZERO; } private void btnPeriod_Click(object sender, EventArgs e) { txtInput.Text += PERIOD; } private void btnDivide_Click(object sender, EventArgs e) { Number temp = new Number(); temp.sign = DIVIDE; temp.ParseSetValue(txtInput.Text); values.Add(temp); txtInput.Text = string.Empty; } private void btnMultiply_Click(object sender, EventArgs e) { Number temp = new Number(); temp.sign = MULTIPLE; temp.ParseSetValue(txtInput.Text); values.Add(temp); txtInput.Text = string.Empty; } private void btnSubtract_Click(object sender, EventArgs e) { Number temp = new Number(); temp.sign = SUBTRACT; temp.ParseSetValue(txtInput.Text); values.Add(temp); txtInput.Text = string.Empty; } private void btnAdd_Click(object sender, EventArgs e) { Number temp = new Number(); temp.sign = ADD; temp.ParseSetValue(txtInput.Text); values.Add(temp); txtInput.Text = string.Empty; } private void btnEquals_Click(object sender, EventArgs e) { string lastSign; Number final = new Number(); Number temp = new Number(); temp.ParseSetValue(txtInput.Text); values.Add(temp); if(values.Count >= 1) { final = values[0]; values.RemoveAt(0); lastSign = final.sign; foreach (Number val in values) { switch (lastSign) { case ADD: final.value += val.value; break; case SUBTRACT: final.value -= val.value; break; case MULTIPLE: final.value *= val.value; break; case DIVIDE: final.value /= val.value; break; } lastSign = val.sign; } } lblResult.Text = final.value.ToString(); values = new List<Number>(); lastSign = string.Empty; txtInput.Text = string.Empty; } private void FormCalc_Load(object sender, EventArgs e) { lblResult.Text = string.Empty; values = new List<Number>(); } } }
FormCalcController.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace NoobToPro { public class FormCalcController { public List<Number> values { get; set; } const string ADD = "+"; const string SUBTRACT = "-"; const string DIVIDE = "/"; const string MULTIPLY = "*"; public FormCalcController() { values = new List<Number>(); } public void setAddition(string inputValue) { Number temp = new Number(); temp.sign = ADD; temp.ParseSetValue(inputValue); values.Add(temp); } public void setSubtract(string inputValue) { Number temp = new Number(); temp.sign = SUBTRACT; temp.ParseSetValue(inputValue); values.Add(temp); } public void setMultiply(string inputValue) { Number temp = new Number(); temp.sign = MULTIPLY; temp.ParseSetValue(inputValue); values.Add(temp); } public void setDivide(string inputValue) { Number temp = new Number(); temp.sign = DIVIDE; temp.ParseSetValue(inputValue); values.Add(temp); } public float setEquals(string finalValue) { string lastSign; Number final = new Number(); Number temp = new Number(); temp.ParseSetValue(finalValue); values.Add(temp); if (values.Count >= 1) { final = values[0]; values.RemoveAt(0); lastSign = final.sign; foreach (Number val in values) { switch (lastSign) { case ADD: final.value += val.value; break; case SUBTRACT: final.value -= val.value; break; case MULTIPLY: final.value *= val.value; break; case DIVIDE: final.value /= val.value; break; } lastSign = val.sign; } } //lblResult.Text = final.value.ToString(); values = new List<Number>(); lastSign = string.Empty; return final.value; //txtInput.Text = string.Empty; } } }
Number.cs
using System; namespace NoobToPro { public class Number { public float value { get; set; } public string sign { get; set; } public void ParseSetValue(string valueToParse) { bool parseSuccess; float temp; parseSuccess = float.TryParse(valueToParse, out temp); if (parseSuccess) { value = temp; } else { throw new Exception("Value was not a number."); } } } }
Next lets look at our tests in the test project.
FormCalcController_Tests.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using NUnit.Framework; using NoobToPro; namespace NoobToPro_Tests { [TestFixture] public class FormCalcController_Tests { FormCalcController fcc; [SetUp] public void SetUp() { fcc = new FormCalcController(); } [TestCase("1.0", 1f)] public void setAddition_test(string inputValue, float expectedValue) { //arrange //act fcc.setAddition(inputValue); //assert Assert.IsTrue(fcc.values.First().sign == "+"); Assert.AreEqual(fcc.values.First().value, expectedValue); } [TestCase("1.0", 1f)] public void setSubtract_test(string inputValue, float expectedValue) { //arrange //act fcc.setSubtract(inputValue); //assert Assert.IsTrue(fcc.values.First().sign == "-"); Assert.AreEqual(fcc.values.First().value, expectedValue); } [TestCase("1.0", 1f)] public void setMultiply_test(string inputValue, float expectedValue) { //arrange //act fcc.setMultiply(inputValue); //assert Assert.IsTrue(fcc.values.First().sign == "*"); Assert.AreEqual(fcc.values.First().value, expectedValue); } [TestCase("1.0", 1f)] public void setDivision_test(string inputValue, float expectedValue) { //arrange //act fcc.setDivide(inputValue); //assert Assert.IsTrue(fcc.values.First().sign == "/"); Assert.AreEqual(fcc.values.First().value, expectedValue); } [TestCase("3.5", "4", "5.0", 12.5f)] public void runEquation_sum_Test(string value1, string value2, string value3, float expectedResult) { //arrange float result; fcc.setAddition(value1); fcc.setAddition(value2); //act result = fcc.setEquals(value3); //assert Assert.AreEqual(expectedResult, result); } [TestCase("3.5", "4", "5.0", -5.5f)] public void runEquation_difference_Test(string value1, string value2, string value3, float expectedResult) { //arrange float result; fcc.setSubtract(value1); fcc.setSubtract(value2); //act result = fcc.setEquals(value3); //assert Assert.AreEqual(expectedResult, result); } [TestCase("3.5", "4", "5.0", 70f)] public void runEquation_product_Test(string value1, string value2, string value3, float expectedResult) { //arrange float result; fcc.setMultiply(value1); fcc.setMultiply(value2); //act result = fcc.setEquals(value3); //assert Assert.AreEqual(expectedResult, result); } [TestCase("3.5", "4", "5.0", 0.175f)] public void runEquation_quotient_Test(string value1, string value2, string value3, float expectedResult) { //arrange float result; fcc.setDivide(value1); fcc.setDivide(value2); //act result = fcc.setEquals(value3); //assert Assert.AreEqual(expectedResult, result); } [TestCase("3.5", "4", "5.0", "1.9", 4.75f)] public void runEquation_multi_Add_Sub_Mult_Test(string value1, string value2, string value3, string value4, float expectedResult) { //arrange float result; fcc.setAddition(value1); fcc.setSubtract(value2); fcc.setMultiply(value3); //act result = fcc.setEquals(value4); //assert Assert.AreEqual(expectedResult, result); } [TearDown] public void TearDown() { fcc = null; } } }
Number_Tests.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using NUnit.Framework; using NoobToPro; namespace NoobToPro_Tests { [TestFixture] public class Number_Tests { Number number; [SetUp] public void Setup() { number = new Number(); } [TestCase("1", 1f)] [TestCase("2", 2f)] [TestCase("3", 3f)] [TestCase("4", 4f)] [TestCase("5", 5f)] [TestCase("6", 6f)] [TestCase("7", 7f)] [TestCase("8", 8f)] [TestCase("9", 9f)] [TestCase("0", 0f)] [TestCase("1.1", 1.1f)] [TestCase("2.9", 2.9f)] [TestCase("3.8", 3.8f)] [TestCase("4.7", 4.7f)] [TestCase("5.6", 5.6f)] public void ParseSetValue_Test_AreEqual(string valueToParse, float expectedValue) { //arrange -done in setup //act number.ParseSetValue(valueToParse); //assert Assert.AreEqual(expectedValue, number.value); } [TestCase(".")] [TestCase("$#.")] [TestCase("$#.432423")] [TestCase("+_/")] [TestCase("'~/?")] public void ParseSetValue_Test_ThrowsException(string valueToParse) { Assert.Throws<Exception>(() => number.ParseSetValue(valueToParse)); } [TearDown] public void TearDown() { number = null; } } }
Is everyone caught up now? Let start with FormCalc.cs. First we want to remove the values from the GUI. We will replace with the FormCalcController object. It will be responsible for maintaining these values.
We will leave the number buttons alone and move onto the add, subtract, multiple and divide buttons’ click events. If you deleted the values like I said above you can use the errors as a guide.
We need to correct the buttons. Lets start with the divide button. Take everything other than the setting txtInput to an empty string. Delete it. Replace it with a call to the controller divide function. Then repeat that for add, subtract and multiple. Remember to correct for which function is being called.
private void btnDivide_Click(object sender, EventArgs e) { controller.setDivide(txtInput.Text); txtInput.Text = string.Empty; }
Now we move to the beast. We move to the equal sign. The easiest way to deal with this one is get rid of everything we used in the FormCalcController setEquals function. Then replace it with a call to setEqual.
private void btnEquals_Click(object sender, EventArgs e) { lblResult.Text = controller.setEquals(txtInput.Text).ToString(); txtInput.Text = string.Empty; }
Finally pull the instantiation of values out of the FormCalc_Load.
Lets see what the final FormCalc.cs looks like after all these changes.
Post Noob to Pro Integrate GUI code – FormCalc.cs
using System; using System.Windows.Forms; using System.Collections.Generic; namespace NoobToPro { public partial class FormCalc : Form { FormCalcController controller = new FormCalcController(); const string ONE = "1"; const string TWO = "2"; const string THREE = "3"; const string FOUR = "4"; const string FIVE = "5"; const string SIX = "6"; const string SEVEN = "7"; const string EIGHT = "8"; const string NINE = "9"; const string ZERO = "0"; const string PERIOD = "."; const string ADD = "+"; const string SUBTRACT = "-"; const string DIVIDE = "/"; const string MULTIPLE = "*"; const string EQUALS = "="; public FormCalc() { InitializeComponent(); } private void btn7_Click(object sender, EventArgs e) { txtInput.Text += SEVEN; } private void btn8_Click(object sender, EventArgs e) { txtInput.Text += EIGHT; } private void btn9_Click(object sender, EventArgs e) { txtInput.Text += NINE; } private void btn4_Click(object sender, EventArgs e) { txtInput.Text += FOUR; } private void btn5_Click(object sender, EventArgs e) { txtInput.Text += FIVE; } private void btn6_Click(object sender, EventArgs e) { txtInput.Text += SIX; } private void btn1_Click(object sender, EventArgs e) { txtInput.Text += ONE; } private void btn2_Click(object sender, EventArgs e) { txtInput.Text += TWO; } private void btn3_Click(object sender, EventArgs e) { txtInput.Text += THREE; } private void btn0_Click(object sender, EventArgs e) { txtInput.Text += ZERO; } private void btnPeriod_Click(object sender, EventArgs e) { txtInput.Text += PERIOD; } private void btnDivide_Click(object sender, EventArgs e) { controller.setDivide(txtInput.Text); txtInput.Text = string.Empty; } private void btnMultiply_Click(object sender, EventArgs e) { controller.setMultiply(txtInput.Text); txtInput.Text = string.Empty; } private void btnSubtract_Click(object sender, EventArgs e) { controller.setSubtract(txtInput.Text); txtInput.Text = string.Empty; } private void btnAdd_Click(object sender, EventArgs e) { controller.setAddition(txtInput.Text); txtInput.Text = string.Empty; } private void btnEquals_Click(object sender, EventArgs e) { lblResult.Text = controller.setEquals(txtInput.Text).ToString(); txtInput.Text = string.Empty; } private void FormCalc_Load(object sender, EventArgs e) { lblResult.Text = string.Empty; } } }
Look at how much smaller this class is after we moved the logic to its own place. Really it was just that easy to integrate all our tested code into this Noob to Pro calculator GUI. Let me know below how you are doing as we approach the end of our time together in the Noob to Pro series down in the comment below.