Windows Calculator in C#

Discussion in 'OT Technology' started by HardTech, Nov 7, 2006.

  1. HardTech

    HardTech hungry

    Joined:
    May 5, 2000
    Messages:
    28,103
    Likes Received:
    1
    Location:
    NorCal
    I'm teaching myself C# and so far it's been fairly simple. I've created the standard "hello world" console-based program and a rudimentary console-based calculator. I decided that those were too easy (I have a few years of experience in Java) and figured I'll create a calculator with a GUI.

    The GUI and button/text box manipulation are all straightforward, but I'm having a bitch of a time getting it to act like Windows Calculator.

    My requirements:
    - When you click on an operand, the first number doesn't go away or turn to 0.
    Example: type in "24" and "*". When you click "*", the "24" doesn't go away until you click on another number.

    To do this, I have two Decimal variables that update the text box whenever I click on a number. Before pushing the operand, the first decimal dFirst updates the text box and after pushing the operand, the second decimal dSecond updates the text box. Pretty straightforward and my requirement above is satisfied if I code it like this, but putting a decimal point is impossible.

    For example, I want to multiply 24 by 30. I click "24", "*", and "30". Everything works perfectly. I am happy.

    Now, I want to multiply 2.4 by 3. I click "2.4", but right after I click "4", the decimal point goes away, leaving me with "24".

    The reason this is because I'm converting between strings and decimals all the time. While strings can have the value "2.", decimals cannot.

    Any suggestions?
     
  2. GOGZILLA

    GOGZILLA Double-Uranium Member

    Joined:
    Jan 16, 2003
    Messages:
    10,760
    Likes Received:
    3
    Location:
    Plantation, FL
    dont convert the numbers from strings until you are actually carrying out the operation
     
  3. HardTech

    HardTech hungry

    Joined:
    May 5, 2000
    Messages:
    28,103
    Likes Received:
    1
    Location:
    NorCal
    then that will cause the first number to go away after I click an operand
     
  4. skinjob

    skinjob Active Member

    Joined:
    Jan 6, 2001
    Messages:
    2,337
    Likes Received:
    0
    Location:
    Aztlán
    You should have a flag indicating that an operand has just been been pressed. If this flag is set, and a number is pressed, then the display should be cleared and the flag reset.
     
  5. HardTech

    HardTech hungry

    Joined:
    May 5, 2000
    Messages:
    28,103
    Likes Received:
    1
    Location:
    NorCal
    Thanks.

    I'm almost done with the program... just some final bugs that will probably take a long time to fix :rant:
     
  6. HardTech

    HardTech hungry

    Joined:
    May 5, 2000
    Messages:
    28,103
    Likes Received:
    1
    Location:
    NorCal
    I'm like 99% done now.. just adding small functions here and there.

    I'll post the final program and the source code for anybody that's interested as soon as I'm done.
     
  7. HardTech

    HardTech hungry

    Joined:
    May 5, 2000
    Messages:
    28,103
    Likes Received:
    1
    Location:
    NorCal
    another problem..

    if I click '9' and '1/x', it gives me 0.1111111111. When I click '1/x' again, it should give me just '9', but it gives me '9.000000000000001'..

    any ideas? :wtc:
     
  8. skinjob

    skinjob Active Member

    Joined:
    Jan 6, 2001
    Messages:
    2,337
    Likes Received:
    0
    Location:
    Aztlán
    I tried it on an old TI calculator I have sitting on my desk and got the same result. It's just floating-point rounding error. I wouldn't worry about it for such a simple program.
     
  9. HardTech

    HardTech hungry

    Joined:
    May 5, 2000
    Messages:
    28,103
    Likes Received:
    1
    Location:
    NorCal
    here's the source code

    Code:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    
    /****************************
     * Created by: Michael Kim  *
     * Date Created: 11/6/2006  *
     * Last Modified: 11/8/2006 *
     * Purpose: Learn C#        *
     ****************************/
    
    /* Notes *
     * Decimals were used due to their high level of precision
     * Backspace is disabled for all answers to calculations and functions
     * Arguments are stored as strings until calculation is done
     * */
    namespace Calculator
    {
        public partial class frmCalc : Form
        {
            bool bOperand = false;  // operand flag
            bool bDecimal = false;  // decimal flag
            bool bEquals = false;   // equals flag
            bool bFunction = false; // function flag (invert/reciprocal)
            string sOperand = "";   // stores the operand sign (+, -, *, /)
            decimal dFirst = 0;     // first argument as decimal
            decimal dSecond = 0;    // second argument as decimal
    
            public frmCalc()
            {
                InitializeComponent();
            }
    
            // clears all flags, arguments, and the screen
            private void btnClear_Click(object sender, EventArgs e)
            {
                txtScreen.Text = "0";
                bOperand = false;
                bDecimal = false;
                bEquals = false;
                bFunction = false;
                dFirst = 0;
                dSecond = 0;
            }
            
            // only works if a number is manually entered
            private void btnBack_Click(object sender, EventArgs e)
            {
                if (txtScreen.Text.Length > 1 && !bEquals && !bOperand && !bFunction)
                {
                    txtScreen.Text = txtScreen.Text.Remove((txtScreen.Text.Length - 1), 1);
                }
                else if (txtScreen.Text.Length == 1)
                {
                    txtScreen.Text = "0";
                }
            }
    
            // if the screen reads '0', the user presses an operand sign, the equals sign, or another function sign,
            // change the screen to read the number on the button
            // otherwise, 
            // append "1" to the end of the screen
            private void btn1_Click(object sender, EventArgs e)
            {
                if (txtScreen.Text.Equals("0") || bOperand || bEquals || bFunction)
                {
                    txtScreen.Text = "1";
                    bOperand = false;
                    bEquals = false;
                    bFunction = false;
                }
                else
                {
                    txtScreen.Text += "1";
                    bEquals = false;
                }
            }
    
            private void btn2_Click(object sender, EventArgs e)
            {
                if (txtScreen.Text.Equals("0") || bOperand || bEquals || bFunction)
                {
                    txtScreen.Text = "2";
                    bOperand = false;
                    bEquals = false;
                    bFunction = false;
                }
                else
                {
                    txtScreen.Text += "2";
                }
            }
    
            private void btn3_Click(object sender, EventArgs e)
            {
                if (txtScreen.Text.Equals("0") || bOperand || bEquals || bFunction)
                {
                    txtScreen.Text = "3";
                    bOperand = false;
                    bEquals = false;
                    bFunction = false;
                }
                else
                {
                    txtScreen.Text += "3";
                }
            }
    
            private void btn4_Click(object sender, EventArgs e)
            {
                if (txtScreen.Text.Equals("0") || bOperand || bEquals || bFunction)
                {
                    txtScreen.Text = "4";
                    bOperand = false;
                    bEquals = false;
                    bFunction = false;
                }
                else
                {
                    txtScreen.Text += "4";
                }
            }
    
            private void btn5_Click(object sender, EventArgs e)
            {
                if (txtScreen.Text.Equals("0") || bOperand || bEquals || bFunction)
                {
                    txtScreen.Text = "5";
                    bOperand = false;
                    bEquals = false;
                    bFunction = false;
                }
                else
                {
                    txtScreen.Text += "5";
                }
            }
    
            private void btn6_Click(object sender, EventArgs e)
            {
                if (txtScreen.Text.Equals("0") || bOperand || bEquals || bFunction)
                {
                    txtScreen.Text = "6";
                    bOperand = false;
                    bEquals = false;
                    bFunction = false;
                }
                else
                {
                    txtScreen.Text += "6";
                }
            }
    
            private void btn7_Click(object sender, EventArgs e)
            {
                if (txtScreen.Text.Equals("0") || bOperand || bEquals || bFunction)
                {
                    txtScreen.Text = "7";
                    bOperand = false;
                    bEquals = false;
                    bFunction = false;
                }
                else
                {
                    txtScreen.Text += "7";
                }
            }
    
            private void btn8_Click(object sender, EventArgs e)
            {
                if (txtScreen.Text.Equals("0") || bOperand || bEquals || bFunction)
                {
                    txtScreen.Text = "8";
                    bOperand = false;
                    bEquals = false;
                    bFunction = false;
                }
                else
                {
                    txtScreen.Text += "8";
                }
            }
    
            private void btn9_Click(object sender, EventArgs e)
            {
                if (txtScreen.Text.Equals("0") || bOperand || bEquals || bFunction)
                {
                    txtScreen.Text = "9";
                    bOperand = false;
                    bEquals = false;
                    bFunction = false;
                }
                else
                {
                    txtScreen.Text += "9";
                }
            }
    
            // if the screen has a non-zero number,
            // append a '0' to the end of the number
            // if the user has clicked an operand sign, the equals sign, or a function button,
            // change the number to '0'
            private void btn0_Click(object sender, EventArgs e)
            {
                if (!txtScreen.Text.Equals("0"))
                {
                    txtScreen.Text += "0";
                }
                else if (bOperand || bEquals || bFunction)
                {
                    txtScreen.Text = "0";
                }
            }
    
            // if the user has clicked equals sign or an operand sign,
            // the second argument starts out as '0', so clicking the decimal button will change the screen to '0.' for future appending
            // if the user has not yet clicked on the decimal button after entering numbers,
            // append a decimal to the end of the screen
            private void btnDec_Click(object sender, EventArgs e)
            {
                if (bEquals || bOperand)
                {
                    txtScreen.Text = "0.";
                    bOperand = false;
                    bEquals = false;
                    bDecimal = true;
                }
                else if (!bDecimal)
                {
                    txtScreen.Text += ".";
                    bOperand = false;
                    bEquals = false;
                    bDecimal = true;
                }
            }
    
            // changes the flags and sOperand string to appropriate values
            // stores the value on the screen as the first argument
            private void btnAdd_Click(object sender, EventArgs e)
            {
                bOperand = true;
                bDecimal = false;
                bEquals = false;
                sOperand = "+";
                dFirst = Convert.ToDecimal(txtScreen.Text);
            }
    
            private void btnSubtract_Click(object sender, EventArgs e)
            {
                bOperand = true;
                bDecimal = false;
                bEquals = false;
                sOperand = "-";
                dFirst = Convert.ToDecimal(txtScreen.Text);
            }
    
            private void btnMultiply_Click(object sender, EventArgs e)
            {
                bOperand = true;
                bDecimal = false;
                bEquals = false;
                sOperand = "*";
                dFirst = Convert.ToDecimal(txtScreen.Text);
            }
    
            private void btnDivide_Click(object sender, EventArgs e)
            {
                bOperand = true;
                bDecimal = false;
                bEquals = false;
                sOperand = "/";
                dFirst = Convert.ToDecimal(txtScreen.Text);
            }
            
            // method that accepts two arguments and a string operand
            // returns the answer as decimal
            private decimal calculate(decimal first, decimal second, string operand)
            {
                decimal answer = 0;
                if (sOperand.Equals("+"))
                {
                    answer = dFirst + dSecond;
                }
                else if (sOperand.Equals("-"))
                {
                    answer = dFirst - dSecond;
                }
                else if (sOperand.Equals("*"))
                {
                    answer = dFirst * dSecond;
                }
                else
                {
                    answer = dFirst / dSecond;
                }
                return answer;
            }
    
            // if the user has already clicked the equals sign, 
            // store the number on the screen to the first variable
            // this way, a user can continue to click on the equals sign and have the same calculation repeated
            // example: '1' '+' '4' <equals> '5' <equals> '9' <equals> '13'
    
            // if the calculation results in an exception, '0' is displayed on the screen and all variables are cleared
            private void btnEquals_Click(object sender, EventArgs e)
            {
                if (bEquals)
                {
                    dFirst = Convert.ToDecimal(txtScreen.Text);
                }
                else
                {
                    dSecond = Convert.ToDecimal(txtScreen.Text);
                }
                try
                {
                    decimal answer = calculate(dFirst, dSecond, sOperand);
                    txtScreen.Text = answer.ToString();
                }
                catch
                {
                    btnClear_Click(sender, e);
                }
    
                //reset variables
                dFirst = 0;
                bOperand = false;
                bDecimal = false;
                bEquals = true;
            }
            
            // displays the screen's square root
            // shows '0' if an exception is thrown
            private void btnSqRt_Click(object sender, EventArgs e)
            {
                try
                {
                    double answer = Convert.ToInt32(txtScreen.Text);
                    answer = Math.Sqrt(answer);
                    txtScreen.Text = answer.ToString();
                    bFunction = true;
                }
                catch
                {
                    btnClear_Click(sender, e);
                }
            }
    
            // if the screen is negative, changes to positive
            // otherwise, changes to negative
            private void btnInvert_Click(object sender, EventArgs e)
            {
                try
                {
                    if (txtScreen.Text.StartsWith("-"))
                    {
                        txtScreen.Text = txtScreen.Text.Remove(0, 1);
                    }
                    else
                    {
                        txtScreen.Text = "-" + txtScreen.Text;
                    }
                    bFunction = true;
                }
                catch
                {
                    btnClear_Click(sender, e);
                }
            }
    
            // displays the screen's reciprocal
            // shows '0' if an exception is thrown
            private void btnReciprocal_Click(object sender, EventArgs e)
            {
                try
                {
                    decimal answer = Convert.ToDecimal(txtScreen.Text);
                    answer = 1 / answer;
                    txtScreen.Text = answer.ToString();
                    bFunction = true;
                }
                catch
                {
                    btnClear_Click(sender, e);
                }
            }
        }
    }
    it's a couple 100K bigger than the Windows calculator :wtc:
     
    Last edited: Nov 8, 2006
  10. deusexaethera

    deusexaethera OT Supporter

    Joined:
    Jan 27, 2005
    Messages:
    19,712
    Likes Received:
    0
    That's because it's running on the .NET Framework. It's not really compiled, not like non-.NET code.
     
  11. HardTech

    HardTech hungry

    Joined:
    May 5, 2000
    Messages:
    28,103
    Likes Received:
    1
    Location:
    NorCal
    I know it's not efficient code. I knew that while I was programming it, and while I tried my best to make it as efficient and aesthetic as possible, it still came out sloppier than what I had hoped.

    Oh well, I guess I have to start somewhere. Any other suggestions for easy-medium difficulty projects? I'm thinking of making a teacher/student records management program... add/remove students, automatically calculate grades, etc. with SQL Express as a backend
     
  12. deusexaethera

    deusexaethera OT Supporter

    Joined:
    Jan 27, 2005
    Messages:
    19,712
    Likes Received:
    0
    I would say, make something you need. Maybe something like MS Money -- that's useful, it always benefits from customization, and it can use a database backend.

    If you make a database app, use an ODBC connection instead of linking straight to the database. That way you can change out the database format whenever you want to, without having to recode your app.
     
  13. HardTech

    HardTech hungry

    Joined:
    May 5, 2000
    Messages:
    28,103
    Likes Received:
    1
    Location:
    NorCal
    Last edited: Nov 9, 2006
  14. HardTech

    HardTech hungry

    Joined:
    May 5, 2000
    Messages:
    28,103
    Likes Received:
    1
    Location:
    NorCal
    I uploaded it to my host.. :hs:
     
  15. crazybenf

    crazybenf Active Member

    Joined:
    Nov 14, 2001
    Messages:
    15,578
    Likes Received:
    3
    But does it convert .999999999 to 1?





    nice app :o
     

Share This Page