1.计算器概述
主要内容是设计开发一个支持连续计算的简单计算器,其过程包括设计目标、设计分析与算法流程、界面设计、关键类图、运行调试与项目扩展。通过该项目的开发,使自己进一步了解基于图形用户界面的Windows应用程序的开发过程。
2.计算器设计
2.1 设计目标
1)简单计算器的实现
该项目是一个支持连续计算的四则运算计算器,通过点击相应的数字按钮和运算按钮,输入并完成如4*6+3、cos(x)或者取倒数等等类似的计算,并将运算结果显示输出在文本框中,同时此计算器也具备清空、退格等其他功能,其运行界面如图1-1所示。
图1-1 简单计算器
计算器是一个简单的单窗口桌面程序,在主窗体上放置了按钮、文本框等控件,通过改变窗体与控件的属性,使界面更加美观与人性化,并为不同的控件添加了相应的事件和可执行的代码,能够完成简单的加减乘除等操作。
2)贷款计算器的实现
首先为计算器增加开平方根、平方、求倒数等功能,使其更加接近科学计算器。
然后在主窗体上增加一个按钮控件,通过点击可以打开贷款计算器的窗口。
图1-2贷款计算器
2.2 设计分析与算法流程
计算器的主要功能是完成加减乘除四则运算,而且支持连续运算,如4+4-7或4×7-6等运算。连续运算的实现借助于数据结构中的Stack(栈),如图1-3所示:首先是输入数字A入栈,然后输入运算符,如果是开方、平方运算则直接输出结果替换数字A,否则将运算符入栈,接着输入数字B入栈;然后,如果输入“=”,则通过出栈计算A OP B,得到计算结果,否则,继续输入其他运算符,重复上述的过程,来实现连续运算。
图1-3简单计算器的算法路程图
2.3 界面设计
2.4 关键类图
btn_A_Click() |
按下数字按钮将值显示在文本框上 |
btn_OP_Click() |
按下操作符将文本框内容与操作入栈 |
btn_backspace_Click() |
将文本框中的内容从右消除一个 |
btn_equal_Click |
计算器的算式计算与结果输出 |
Tips:
A为0-9十个数字;
OP为+-×÷等。
3.计算器实现(运行调试)
4.计算器扩展
计算_Click() |
贷款计算输出 |
5.总结
1)Stack(栈)的用法总结
为了使计算器支持连续计算,在项目中使用了Stack 类,Stack 类表示对象的简单后进先出非泛型集合,它位于 System.Collections命名空间中,它的特点是:后进先出的集合,Stack能接受空引用作为有效值并且允许重复的元素。
Stack常用的方法及属性如下:
public virtual void Clear(); |
从 Stack 中移除所有的元素 |
public virtual bool Contains( object obj ); |
判断某个元素是否在 Stack 中 |
public virtual object Peek(); |
返回在 Stack 的顶部的对象,但不移除它 |
public virtual object Pop(); |
移除并返回在 Stack 的顶部的对象 |
public virtual void Push( object obj ); |
向 Stack 的顶部添加一个对象 |
2)DialogResult方法
方法名称 |
说明 |
AbortRetryIgnore |
提供“中止”、“重试”和“忽略”三个按钮 |
OK |
提供“确定按钮” |
OKCancel |
提供“确定”和“取消”两个按钮 |
RetryCancel |
提供“重试”和“取消”两个按钮 |
YesNo |
提供“是”和“否”两个按钮 |
YesNoCancel |
提供“是”、“否”和“取消”三个按钮 |
3)主要代码与分析
①计算器
private void btn_equal_Click(object sender, EventArgs e)
{
try
{
st.Push(txtDisplay.Text);
if (st.Count >= 3)
{
num1 = Convert.ToDouble(st.Pop());
Operator = Convert.ToString(st.Pop());
num2 = Convert.ToDouble(st.Pop());
switch (Operator)
{
case "+":
tempresult = num2 + num1;
st.Push(tempresult);
break;
case "-":
tempresult = num2 - num1;
st.Push(tempresult);
break;
case "×":
tempresult = num2 * num1;
st.Push(tempresult);
break;
case "÷":
tempresult = num2 / num1;
st.Push(tempresult);
break;
}
txtDisplay.Text = tempresult.ToString();
}
st.Clear();
flag2 = true;
}
catch (Exception)
{
MessageBox.Show("先输入数字才能进行此运算!", "Error", MessageBoxButtons.OK);
}
}
上面的代码是按下等于后的计算,首先将txtDisplay中显示的数字字符串Push进栈中,如果栈中的项大于或等于三个就可以进行运算。之后再用switch语句来判断操作符OP是+、-、×、÷中的哪个,然后在进行运算。
注意:num1是后进入的数字,num2是先进入的数字。如,5-6,num1即为6,num2即为5。
private void btn_7_Click(object sender, EventArgs e)
{
if (flag2)
{
flag2 = false;
txtDisplay.Text = "7";
}
else if (flag)
{
txtDisplay.Text += "7";
}
else
{
flag = true;
txtDisplay.Text = "7";
}
}
private void btn_equal_Click(object sender, EventArgs e)
{
try
{
st.Push(txtDisplay.Text);
if (st.Count >= 3)
{
num1 = Convert.ToDouble(st.Pop());
Operator = Convert.ToString(st.Pop());
num2 = Convert.ToDouble(st.Pop());
switch (Operator)
{
case "+":
tempresult = num2 + num1;
st.Push(tempresult);
break;
case "-":
tempresult = num2 - num1;
st.Push(tempresult);
break;
case "×":
tempresult = num2 * num1;
st.Push(tempresult);
break;
case "÷":
tempresult = num2 / num1;
st.Push(tempresult);
break;
}
txtDisplay.Text = tempresult.ToString();
}
st.Clear();
flag2 = true;
}
catch (Exception)
{
MessageBox.Show("先输入数字才能进行此运算!", "Error", MessageBoxButtons.OK);
}
}
上面的代码是按下等于后的计算,首先将txtDisplay中显示的数字字符串Push进栈中,如果栈中的项大于或等于三个就可以进行运算。之后再用switch语句来判断操作符OP是+、-、×、÷中的哪个,然后在进行运算。
注意:num1是后进入的数字,num2是先进入的数字。如,5-6,num1即为6,num2即为5。
private void btn_7_Click(object sender, EventArgs e)
{
if (flag2)
{
flag2 = false;
txtDisplay.Text = "7";
}
else if (flag)
{
txtDisplay.Text += "7";
}
else
{
flag = true;
txtDisplay.Text = "7";
}
}
private void btn_per_Click(object sender, EventArgs e)
{
double num;
try
{
st.Push(txtDisplay.Text);
num = Convert.ToDouble(st.Pop());
st.Push(num * 0.01);
txtDisplay.Text = (num * 0.01).ToString();
flag2 = true;
}
catch (Exception)
{
MessageBox.Show("请先输入一个数字!", "Error", MessageBoxButtons.OK);
}
}
private void btn_sqrt_Click(object sender, EventArgs e)
{
double num;
try
{
st.Push(txtDisplay.Text);
num = Convert.ToDouble(st.Pop());
st.Push(Math.Sqrt(num));
txtDisplay.Text = Math.Sqrt(num).ToString();
flag2 = true;
}
catch (Exception)
{
MessageBox.Show("请先输入一个数字!", "Error", MessageBoxButtons.OK);
}
}
private void btn_ping_Click(object sender, EventArgs e)
{
double num;
try
{
st.Push(txtDisplay.Text);
num = Convert.ToDouble(st.Pop());
st.Push(Math.Pow(num, 2));
txtDisplay.Text = Math.Pow(num, 2).ToString();
flag2 = true;
}
catch (Exception)
{
MessageBox.Show("请先输入一个数字!", "Error", MessageBoxButtons.OK);
}
}
private void btn_dai_Click(object sender, EventArgs e)
{
var fm = new Mortgage();
fm.ShowDialog();
}
private void btn_re_Click(object sender, EventArgs e)
{
double num;
try
{
st.Push(txtDisplay.Text);
num = Convert.ToDouble(st.Pop());
st.Push(1 / num);
txtDisplay.Text = (1 / num).ToString();
flag2 = true;
}
catch (Exception)
{
MessageBox.Show("请先输入一个数字!", "Error", MessageBoxButtons.OK);
}
}
private void btn_backspace_Click(object sender, EventArgs e)
{
try
{
txtDisplay.Text = txtDisplay.Text.Substring(0, txtDisplay.Text.Length - 1);
}
catch (Exception)
{
}
}
private void btn_clear_Click(object sender, EventArgs e)
{
txtDisplay.Text = "";
st.Clear();
flag = true; flag2 = false;
}
tip:上面的flag2是来判断是否计算出结果,如果得出结果,那么可以利用这个flag2来判断下次按下数字按键的时候是否会清空txtDisplay内容,并加入按下的数字。
②贷款计算器
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Calculator
{
public partial class Mortgage : Form
{
public Mortgage()
{
InitializeComponent();
}
private void Mortgage_Load(object sender, EventArgs e)
{
}
private void Mortgage_FormClosed(object sender, FormClosedEventArgs e)
{
}
private void 计算_Click(object sender, EventArgs e)
{
if(string.IsNullOrEmpty(贷款年限.Text)||string.IsNullOrEmpty(贷款金额.Text)|| string.IsNullOrEmpty(贷款利率.Text))
{
MessageBox.Show("请填写完整数据!", "Error", MessageBoxButtons.OK);
}
else
{
double yearM, money, rate;
double moHuan, moLi, moZli;
yearM = Convert.ToDouble(贷款年限.Text) * 12;
money = Convert.ToDouble(贷款金额.Text) * 10000;
rate = Convert.ToDouble(贷款利率.Text) / 1200;
if (等额本息.Checked)
{
moHuan = money * rate * Math.Pow(1 + rate, yearM) / (Math.Pow(1 + rate, yearM) - 1);
moLi = moHuan * yearM - money;
moZli = moHuan * yearM;
月均还款.Text = moHuan.ToString("0.00");
利息总额.Text = moLi.ToString("0.00");
还款总额.Text = moZli.ToString("0.00");
}
else
{
moHuan = (money / yearM) + (money - money) * rate;
moLi = (money / yearM + money * rate + money / yearM * (1 + rate)) / 2 * yearM - money;
moZli = (money / yearM + money * rate + money / yearM * (1 + rate)) / 2 * yearM;
月均还款.Text = moHuan.ToString("0.00");
利息总额.Text = moLi.ToString("0.00");
还款总额.Text = moZli.ToString("0.00");
}
}
}
private void 重新计算_Click(object sender, EventArgs e)
{
贷款年限.Text = "";
贷款金额.Text = "";
贷款利率.Text = "";
月均还款.Text = "";
利息总额.Text = "";8
还款总额.Text = "";
}
}
}
贷款计算器主要是公式的运用,比如计算结果是double型,最后要将计算结果显示在文本框中。
首先判断等额本息被选中,然后调用Math中的方法加以简化算式,使得代码更加简洁。