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

识字粗堪供赋役,不须辛苦慕公卿。这篇文章主要讲述#yyds干货盘点#制作简易计算器相关的知识,希望能为你提供帮助。
今天确实没什么可写的。就来搞一个小的实战项目吧:带有注册功能的简易计算器。
零、设计软件界面我们设计的软件一共有两个,一个是用户使用的计算器,它包含两个 Form 窗口 软件注册窗口 和 计算器窗口 ,其中软件注册窗口主要是提供机器码和注册软件功能。另一个软件是软件开发商所使用的注册机,通过它开发商可以利用机器码生成注册码。下面我们分别来看一下计算器和注册机界面的设计。
0.1 计算器界面首先我们来看一下注册界面。界面很简单,包含一个机器码显示框,一个注册码输入框和一个复制机器码的按钮以及注册软件的按钮。这个窗口的具体代码实现我会在后面的文章中进行讲解。

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

文章图片

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

文章图片

这个项目的目录结构如下,
#yyds干货盘点#制作简易计算器

文章图片

Data 目录中放置了项目要用到的实体类,并且该实体类继承 INotifyPropertyChanged 接口,当属性发生变化时,变化后的数据会直接显示在界面中。
Method 目录存放了我们的软件实现科学计算器和标准计算器功能的方法。
View 目录是自定义控件目录,用于在我们选择不同类型计算器时显示不同的界面。
MainForm 是计算器的主窗体。
Registerd 是注册窗体。
0.2 注册机界面我们再来看一下注册机界面。注册机界面跟计算器的注册窗体很像,只不过就是将复制机器码按钮改为了复制注册码按钮,注册按钮改为了生成注册码按钮。注册记得代码我将在后续文章中逐步讲解。
#yyds干货盘点#制作简易计算器

文章图片

注册机项目的目录结构如下。
#yyds干货盘点#制作简易计算器

文章图片

一、计算器代码编写这里我们知道计算器的核心代码,代码中已经写好备注。
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++; //当前数据不是小数,追加到此数据之后,按照以下规则 elseB[--j] = (double.Parse(B[j]) * 10 + Convert.ToDouble(ch.ToString())) + ""; ++j; elseindex = i; //记录当前数字的索引 B[j++] = ch + ""; elseif (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))doch1 = (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.Methodpublic 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 "x2"; 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", "√", "x2", "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的方法计算出结果 tryswitch (name)case "square": SetText2 = GetTxet2 + "(" + GetText1 + ")2"; 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; elseexpression = 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; elseexpression = 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); elseSetText2 = 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"; elseSetText1 = 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; elseSetText1 = "error"; SetText2 = "error"; public string Caculate()string str = expression; //调用算术表达式解析算法 double result = 0; //捕获异常 tryAnalyExpression.AnalyExpressions(str, out result); catch (Exception e)result = 0; return "error"; //出现异常返回errorreturn 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干货盘点#制作简易计算器】以上两种方法都可以使用,各位读者可以根据自己的习惯来选择,但是我还是推荐使用方法二,因为在企业级桌面项目中方法二的实现不消耗过多的资源。
三、总结本篇文章主要展示并讲解了计算器和注册机界面的设计,以及计算器功能的简单实现,并讲解了如何实现注册界面跳转到功能界面。本阶段后面的文章将以这篇文章为基础去逐步完善计算机的功能,并实现一机一码功能。

    推荐阅读