#yyds干货盘点#制作简易计算器

Posted 494324190

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#yyds干货盘点#制作简易计算器相关的知识,希望对你有一定的参考价值。

今天确实没什么可写的。就来搞一个小的实战项目吧:带有注册功能的简易计算器。

零、设计软件界面

我们设计的软件一共有两个,一个是用户使用的计算器,它包含两个 Form 窗口 软件注册窗口计算器窗口 ,其中软件注册窗口主要是提供机器码和注册软件功能。另一个软件是软件开发商所使用的注册机,通过它开发商可以利用机器码生成注册码。下面我们分别来看一下计算器和注册机界面的设计。

0.1 计算器界面

首先我们来看一下注册界面。界面很简单,包含一个机器码显示框,一个注册码输入框和一个复制机器码的按钮以及注册软件的按钮。这个窗口的具体代码实现我会在后面的文章中进行讲解。

接下来我们再来看一下计算器界面。这其实就是一个简单的计算器,可以通过 Menu 下拉按钮来选择是科学计算器还是标准计算器。

这个项目的目录结构如下,

Data 目录中放置了项目要用到的实体类,并且该实体类继承 INotifyPropertyChanged 接口,当属性发生变化时,变化后的数据会直接显示在界面中。
Method 目录存放了我们的软件实现科学计算器和标准计算器功能的方法。
View 目录是自定义控件目录,用于在我们选择不同类型计算器时显示不同的界面。
MainForm 是计算器的主窗体。
Registerd 是注册窗体。

0.2 注册机界面

我们再来看一下注册机界面。注册机界面跟计算器的注册窗体很像,只不过就是将复制机器码按钮改为了复制注册码按钮,注册按钮改为了生成注册码按钮。注册记得代码我将在后续文章中逐步讲解。

注册机项目的目录结构如下。

一、计算器代码编写

这里我们知道计算器的核心代码,代码中已经写好备注。

using System;
using System.Collections;

namespace Calculator.Method

    /// <summary>
    /// 将中缀表达式翻译成后缀表达式
    /// 输入中缀表达式: A+B*(C+D)-E/F
    /// 翻译成后缀表达式:ABCD+*+EF/-
    /// 中缀表达式翻译成后缀表达式的方法如下:
    /// (1)从左向右依次取得数据ch
    /// (2)如果ch是操作数,直接输出
    /// (3)如果ch是运算符(含左右括号),则:
    /// a:如果ch = "(",放入堆栈
    /// b:如果ch = ")",依次输出堆栈中的运算符, 直到遇到"("为止
    /// c:如果ch不是")"或者"(",那么就和堆栈顶点 位置的运算符top做优先级比较
    /// 1:如果ch优先级比top高,那么 将ch放入堆栈
    /// 2:如果ch优先级低于或者等于 top,那么输出top,然后将ch放入堆栈
    /// (4)如果表达式已经读取完成,而堆栈中还有运算符时,依次由顶端输出
    /// </summary>
    public class AnalyExpression
    
        //声明表达式并赋初值
        public static string expression;

        //声明堆栈
        private static Stack myStack = new Stack();

        //作为主函数,供外界调用,传入参数为表达式,输出参数为解析并计算表达式之后的结果
        public static void AnalyExpressions(string exp, out double res)
        

            //将表达式赋值为传进来的参数exp
            expression = exp;

            //对B初始化,每一个索引全部赋值为空
            for (int i = 0; i < B.Length; i++)
            
                B[i] = null;
            

            //调用解析方法,将中缀表达式解析为类似的“后缀表达式”
            Parse();
            //调用计算方法,对“后缀表达式”进行计算,返回计算结果
            res = Calculate();
        

        //声明数组,将中缀表达式解析之后放入此数组中
        static string[] B = new string[100];

        //标记一个多位数字是否为小数(带小数点)
        static bool haspoint;
        //标记小数位的位数,从1开始计数
        static int figure = 1;

        //将中缀表达式解析成后缀表达式
        public static void Parse()
        
            int i, j = 0;
            string ch, ch1;

            char[] A = expression.ToCharArray(); //将字符串转成字符数组
            int length = A.Length;
            int index = 1;  //记录当前数字的索引

            for (i = 0; i < length; i++)
            
                ch = A[i] + "";     //对字符之后添加一个空引号,以隐式转换为字符串
                                    //强制转换字符char为字符串string会转换为对应的ASCII码

                if (IsOperand(ch)) //如果是操作数,直接放入B中
                
                    //中缀表达式被分解为字符数组,因此在支持两位以上的数字时
                    //首先记录一个数字的索引,假如第二个数字的索引与第一个数字的索引之差为1
                    //则说明两个数字应组成为一个多位数
                    if (index == i - 1)
                    
                        index = i;
                        //如果当前字符为小数点,则在数组B上一个索引后追加“.0”,并标记当前数据为小数
                        if (ch == ".")
                        
                            B[--j] = B[j] + ".0";
                            haspoint = true;
                        
                        //如果当前数据为小数,则之后的字符追加到此数据之后,按照以下规则
                        else if (haspoint)
                        
                            B[--j] = (double.Parse(B[j])) + Convert.ToDouble(ch.ToString()) * (1 / (Math.Pow(10, figure))) + "";
                            figure++;
                        
                        //当前数据不是小数,追加到此数据之后,按照以下规则
                        else
                        
                            B[--j] = (double.Parse(B[j]) * 10 + Convert.ToDouble(ch.ToString())) + "";
                        
                        ++j;
                    
                    else
                    
                        index = i;      //记录当前数字的索引
                        B[j++] = ch + "";
                    

                

                else
                
                    if (ch == "(") //如果是“(”,将它放入堆栈中
                        myStack.Push(ch);
                    else if (ch == ")") //如果是“)”
                    
                        while (!IsEmpty(myStack)) //不停地弹出堆栈中的内容,直到遇到“(”
                        
                            ch = (string)myStack.Pop();
                            if (ch == "(")
                                break;
                            else
                                B[j++] = ch + ""; //将堆栈中弹出的内容放入B中
                        
                    
                    else //既不是“(”,也不是“)”,是其它操作符,比如 +, -, *, / 之类的
                    
                        if (!IsEmpty(myStack))
                        
                            do
                            
                                ch1 = (string)myStack.Pop();//弹出栈顶元素
                                if (Priority(ch) > Priority(ch1)) //如果栈顶元素的优先级小于读取到的操作符
                                
                                    myStack.Push(ch1);//将栈顶元素放回堆栈
                                    myStack.Push(ch);//将读取到的操作符放回堆栈
                                    break;
                                
                                else//如果栈顶元素的优先级比较高或者两者相等时
                                
                                    B[j++] = ch1 + ""; //将栈顶元素弹出,放入B中
                                    if (IsEmpty(myStack))
                                    
                                        myStack.Push(ch); //将读取到的操作符压入堆栈中
                                        break;
                                    
                                
                             while (!IsEmpty(myStack));
                        
                        else //如果堆栈为空,就把操作符放入堆栈中
                        
                            myStack.Push(ch);
                        
                    
                
            

            while (!IsEmpty(myStack))
            
                B[j++] = myStack.Pop() + "";//将堆栈中剩下的操作符输出到B中
            
        
        //计算“后缀表达式”的值
        public static double Calculate()
        
            int i;
            double no1, no2, ret;
            string ch;

            //把B中的null值去掉
            int n = 0;
            for (; n < B.Length; n++)
            
                if (B[n] == null)
                
                    break;
                
            

            string[] A = new string[n];
            //将B的非null数据复制到A中
            for (n = 0; n < A.Length; n++)
            
                A[n] = B[n];
            

            myStack.Clear();

            for (i = 0; i < A.Length; i++)
            
                ch = A[i];
                if (IsOperand(ch))//如果是操作数,直接 压入栈
                
                    myStack.Push(double.Parse(ch));
                
                else //如果是操作符,就弹出两个数字来进行运算
                
                    no1 = (double)myStack.Pop();
                    no2 = (double)myStack.Pop();
                    ret = GetValue(ch, no1, no2);
                    myStack.Push(ret);//将结果压入栈
                
            

            return (double)myStack.Pop();//弹出最后的运算结果
        

        //对两个值利用运算符计算结果
        private static double GetValue(string op, double ch1, double ch2)
        
            switch (op)
            
                case "+":
                    return ch2 + ch1;
                case "-":
                    return ch2 - ch1;
                case "*":
                    return ch2 * ch1;
                case "/":
                    return ch2 / ch1;
                default:
                    return 0;
            
        

        //判断堆栈是否为空
        private static bool IsEmpty(Stack st)
        
            return st.Count == 0 ? true : false;
        

        //判断是否是操作数
        private static bool IsOperand(string ch)
        
            string[] operators =  "+", "-", "*", "/", "(", ")" ;
            for (int i = 0; i < operators.Length; i++)
                if (ch == operators[i])
                    return false;

            return true;
        

        //返回运算符的优先级
        private static int Priority(string ch)
        
            int priority;

            switch (ch)
            
                case "+":
                    priority = 1;
                    break;
                case "-":
                    priority = 1;
                    break;
                case "*":
                    priority = 2;
                    break;
                case "/":
                    priority = 2;
                    break;
                default:
                    priority = 0;
                    break;
            

            return priority;
        
    



using System;

namespace Calculator.Method

    public class PrintAndExpression
    
        //获取控件名称,返回数字或者操作符
        public string GetValue(string name)
        
            switch (name)
            
                case "one":
                    return "1";
                case "two":
                    return "2";
                case "three":
                    return "3";
                case "four":
                    return "4";
                case "five":
                    return "5";
                case "six":
                    return "6";
                case "senven":
                    return "7";
                case "eight":
                    return "8";
                case "nine":
                    return "9";
                case "zero":
                    return "0";
                case "point":
                    return ".";
                case "mod":
                    return "Mod";
                case "radication":
                    return "√";
                case "square":
                    return "x²";
                case "daoshu":
                    return "1⁄x";
                case "CE":
                    return "CE";
                case "C":
                    return "C";
                case "delete":
                    return "delete";
                case "div":
                    return "/";
                case "multiply":
                    return "*";
                case "sub":
                    return "-";
                case "add":
                    return "+";
                case "minus":
                    return "±";
                case "mi":
                    return "x^y";
                case "sin":
                    return "sin";
                case "tan":
                    return "tan";
                case "cos":
                    return "cos";
                case "shimi":
                    return "10^x";
                case "log":
                    return "log";
                case "exp":
                    return "exp";
                case "pi":
                    return "3.14";
                case "fact":
                    return "n!";
                case "left":
                    return "(";
                case "right":
                    return ")";
                case "per":
                    return "%";
                case "equal_sign":
                    return "=";
                default:
                    return "";
            
        

        //判断是操作符还是数字,一元操作符还是二元操作符
        //数字,小数点,pi及正负号返回0
        //一元操作符返回1
        //二元操作符返回2
        //否则返回-1
        public int Is0peration(string name)
        
            string[] Digital =  "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", ".", "3.14" ;
            string[] UnaryOperators =  "Mod", "√", "x²", "1⁄x", "±", "sin", "cos", "tan", "10^x", "log", "exp", "n!" ;
            string[] BinaryOperators =  "/", "*", "-", "+", "(", ")" ;

            foreach (string item in Digital)
            
                if (GetValue(name) == item)
                
                    return 0;               //数字
                
            
            foreach (string item in UnaryOperators)
            
                if (GetValue(name) == item)
                
                    return 1;               //一元运算符
                
            
            foreach (string item in BinaryOperators)
            
                if (GetValue(name) == item)
                
                    return 2;               //二元运算符
                
            
            return -1;
        

        //求一个数的阶乘,并返回结果
        public float Fact(string number1)
        
            float n = float.Parse(number1);
            float i = n;
            for (; n > 1; n--)
            
                i = i * n - 1;
            
            return i;
        

        //保存表达式
        public static string expression;

        public void PrintText(string name, string GetText1, string GetTxet2, out string SetText1, out string SetText2)
        
            //每按下一个按钮,将按钮所表示的含义打印到TextBlock中
            //如果为数字(包括多位数),暂时保存在SetText1中。即下方那一栏文本框
            //如果为一元运算符,将GetText1中的数字连同一元运算符一并保存到SetText2中,表达式直接获得一元运算符计算结果
            //如果为二元运算符,将GetText1中的数字连同二元运算符一并保存到SetText2中。

            //判断str1是否含有等号。和算术表达式异常提示信息。则先清空。
            if (GetText1 != null && GetText1.Contains("="))
            
                GetTxet2 = null;
                GetText1 = null;
            
            else if (GetText1 == "你的算式无法计算" || GetText1 == "除数不能为零" || GetText1 == "输入无效")
            
                GetTxet2 = null;
                GetText1 = null;
            

            //是否为操作符,数字
            int isOperation = Is0peration(name);

            if (isOperation == 0)       //数字
            
                if(GetText1=="0")
                
                    GetText1 = "";
                
                SetText2 = GetTxet2;
                SetText1 = GetText1 + GetValue(name);     //显示

                //expression = GetTxet2;
            
            else if (isOperation == 1)  //一元运算符
            
                SetText1 = GetText1;
                //对于一元运算符直接调用Math的方法计算出结果
                try
                
                    switch (name)
                    
                        case "square":
                            SetText2 = GetTxet2 + "(" + GetText1 + ")²";
                            expression = expression + float.Parse(GetText1) * float.Parse(GetText1) + "";
                            break;
                        case "sin":
                            SetText2 = GetTxet2 + GetValue(name) + "(" + GetText1 + ")";
                            expression = expression + Math.Sin(float.Parse(GetText1)) + "";
                            break;
                        case "cos":
                            SetText2 = GetTxet2 + GetValue(name) + "(" + GetText1 + ")";
                            expression = expression + Math.Cos(float.Parse(GetText1)) + "";
                            break;
                        case "tan":
                            SetText2 = GetTxet2 + GetValue(name) + "(" + GetText1 + ")";
                            expression = expression + Math.Tan(float.Parse(GetText1)) + "";
                            break;
                        case "radication":
                            SetText2 = GetTxet2 + GetValue(name) + "(" + GetText1 + ")";
                            expression = expression + Math.Sqrt(float.Parse(GetText1)) + "";
                            break;
                        case "shimi":
                            SetText2 = GetTxet2 + "10^" + GetText1;
                            expression = expression + Math.Pow(10, float.Parse(GetText1)) + "";
                            break;
                        case "fact":
                            SetText2 = GetTxet2 + GetText1 + "!";
                            expression = expression + Fact(GetText1) + "";
                            break;
                        case "minus":                                                   //负号
                            SetText2 = GetTxet2 + "(" + "-" + GetText1 + ")";
                            expression = expression + "(0" + "-" + GetText1 + ")";
                            break;
                        case "daoshu":
                            SetText2 = GetTxet2 + "1⁄" + GetText1;
                            if (0 == int.Parse(GetText1))
                            
                                SetText1 = "除数不能为零";
                                break;
                            
                            else
                            
                                expression = expression + 1 / float.Parse(GetText1) + "";
                            
                            break;
                        case "exp":
                            SetText2 = GetTxet2 + "exp(" + GetText1 + ")";
                            expression = expression + Math.Exp(float.Parse(GetText1)) + "";
                            break;
                        case "log":
                            SetText2 = GetTxet2 + "log(" + GetText1 + ")";
                            if (0 == int.Parse(GetText1))
                            
                                SetText1 = "输入无效";
                                break;
                            
                            else
                            
                                expression = expression + Math.Log(float.Parse(GetText1)) + "";
                            
                            break;
                        default:
                            SetText2 = GetTxet2;
                            SetText1 = "计算错误";
                            break;
                    
                    SetText1 = "";
                    GetText1 = "";
                
                catch (Exception e)
                
                    SetText1 = "输入无效";
                    SetText2 = "";
                
            
            else if (isOperation == 2)  //二元运算符
            
                //如果运算符为左括号
                if (name == "left")
                
                    SetText2 = GetTxet2 + GetValue(name);
                    SetText1 = "";
                    expression = expression + GetValue(name);
                
                //如果运算符为右括号
                else if (name == "right")
                
                    SetText2 = GetTxet2 + GetText1 + GetValue(name);
                    SetText1 = "";
                    expression = expression + GetText1 + GetValue(name);
                
                else
                
                    SetText2 = GetTxet2 + GetText1 + GetValue(name);    //显示
                    SetText1 = "";

                    expression = expression + GetText1 + GetValue(name);
                
            
            else if (GetValue(name) == "delete")
            
                //将Text1中的数依次删除
                SetText2 = GetTxet2;
                if(GetText1!="0"&&GetText1!=null&&GetText1!="")
                
                    SetText1 = GetText1.Remove(GetText1.Length - 1, 1);
                
                else if(GetText1==null)
                
                    SetText1 = "0";
                
                else
                
                    SetText1 = GetText1;
                
                expression = GetTxet2;
            
            else if (GetValue(name) == "CE")
            
                //将Text1中的数清空
                SetText2 = GetTxet2;
                SetText1 = "0";
                expression = GetTxet2;
            
            else if (GetValue(name) == "C")
            
                //清空所有内容
                SetText2 = "";
                SetText1 = "0";
                expression = null;
            
            else if (GetValue(name) == "=")
            
                SetText2 = GetTxet2 + GetText1;
                expression = expression + GetText1;

                if (expression == null)
                
                    SetText1 = "";
                
                else
                
                    //添加一个等号,标记为计算结果。再输入数字的时候应该先清空。
                    //SetText1 = "=" + Caculate();
                    string result = Caculate();
                    SetText1 = result == "error" ? "你的算式无法计算" : "=" + result;
                
            
            else
            
                SetText1 = "error";
                SetText2 = "error";
            
        
        public string Caculate()
        
            string str = expression;
            //调用算术表达式解析算法   
            double result = 0;

            //捕获异常
            try
            
                AnalyExpression.AnalyExpressions(str, out result);
            
            catch (Exception e)
            
                result = 0;
                return "error"; //出现异常返回error
            
            return result + "";
        
    

二、注册界面跳转

当我们注册成功后,就需要跳转到功能窗体去。对于这个跳转功能有两种方法,一种是隐藏注册窗体,显示功能窗体,另一种是采用 DialogResult 来实现,下面我们分别来看一下这两种方法的代码如何编写。
方法一,在注册按钮的 click 事件上上编写如下代码:

this.Visible=false;//隐藏当前窗体
MainForm mf = new MainForm();
mf.Show();//显示功能窗体。

方法二,将程序入口点文件 Program 文件的 Main 方修改如下:

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//先显示窗体Registerd
Registerd r=new Registerd();
if(r.ShowDialog()==DialogResult.OK)//当窗体Registerd关闭时再打开MainForm船体

    Application.Run(new MainForm());

接着在 Registerd 窗体的注册按钮的 click 事件中增加如下代码:

this.DialogResult=DialogResult.OK;

以上两种方法都可以使用,各位读者可以根据自己的习惯来选择,但是我还是推荐使用方法二,因为在企业级桌面项目中方法二的实现不消耗过多的资源。

三、总结

本篇文章主要展示并讲解了计算器和注册机界面的设计,以及计算器功能的简单实现,并讲解了如何实现注册界面跳转到功能界面。本阶段后面的文章将以这篇文章为基础去逐步完善计算机的功能,并实现一机一码功能。

以上是关于#yyds干货盘点#制作简易计算器的主要内容,如果未能解决你的问题,请参考以下文章

#yyds干货盘点#Prometheus 之 PromQL 介绍

#yyds干货盘点# 解决华为机试:字符串通配符

#yyds干货盘点# 更高级别的抽象---函数式思想

百行代码制作一个属于猫主子的3D场景照片墙#yyds干货盘点#

#yyds干货盘点#nginx路径重写

#yyds干货盘点#Python训练营Python每日一练----第26天:后缀表达式