识字粗堪供赋役,不须辛苦慕公卿。这篇文章主要讲述#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++;
//当前数据不是小数,追加到此数据之后,按照以下规则
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干货盘点#制作简易计算器】以上两种方法都可以使用,各位读者可以根据自己的习惯来选择,但是我还是推荐使用方法二,因为在企业级桌面项目中方法二的实现不消耗过多的资源。
三、总结本篇文章主要展示并讲解了计算器和注册机界面的设计,以及计算器功能的简单实现,并讲解了如何实现注册界面跳转到功能界面。本阶段后面的文章将以这篇文章为基础去逐步完善计算机的功能,并实现一机一码功能。
推荐阅读
- Apache 网页与安全优化
- python 全解坦克大战 辅助类 附完整代码雏形
- 关于C#/.NET程序中的应用程序域程序集线程区域性的个人理解
- Flutter 专题57 图解页面小跳转#yyds干货盘点#
- 建议收藏 | SpringBoot 元数据配置原来可以这么拓展!
- 微服务架构 | 3.2 Alibaba Nacos 注册中心 #yyds干货盘点#
- 隐藏了2年的Bug,终于连根拔起,悲观锁并没有那么简单
- #yyds干货盘点#web安全day47(口令字典crunchcupphydraMSF-psexec_psh的使用)
- #yyds干货盘点# Spring的@Autowired依赖注入原来这么多坑!