学了快一年的c/c++,除了c语言能用来解数学题,c++多了个面向对象以外,什么都不会(可能在下学术不精,各位大佬勿喷)。最近老师在讲vc++,终于可以做个真正的应用程序出来了,莫名有些兴奋,所以废了九牛二虎之力用MFC做了个简易计算器,话不多说,先看界面。
下面一步步开始说明代码部分
1. 创建并初始化全局变量
public:
CString num1;//用来绑定用户输入的第一个操作数
CString num2;//用来绑定用户输入的第二个操作数
CString IsTemple;//判断进行的是哪个运算符
CString smallnum1;//判断输入的第一个数是否是小数
CString smallnum2;//判断输入的第二个数是否是小数
num1 = "";
num2 = "";
IsTemple = "";
m_output = "0";
smallnum1 = "";
smallnum2 = "";
(m_output是我给输出框绑定的变量,也初始化)这里稍微说一下,为什么m_output要初始化为“0”,读者打开自己电脑上的计算器就知道了,计算器不论是归零,或是默认状态,输出框显示的都不为空,而是“0”,这里我们也尽量做到和真实的计算器一样。以上,第一部分,创建并初始化全局变量就算完成了。
2. 数字按钮代码的实现
void CCalc1Dlg::On1()
{
if(m_output == "0")
{
m_output = "";
UpdateData(FALSE);
}
m_output += "1";
UpdateData(FALSE);
}
void CCalc1Dlg::On2()
{
if(m_output == "0")
{
m_output = "";
UpdateData(FALSE);
}
m_output += "2";
UpdateData(FALSE);
}
void CCalc1Dlg::On3()
{
if(m_output == "0")
{
m_output = "";
UpdateData(FALSE);
}
m_output += "3";
UpdateData(FALSE);
}
void CCalc1Dlg::On4()
{
if(m_output == "0")
{
m_output = "";
UpdateData(FALSE);
}
m_output += "4";
UpdateData(FALSE);
}
void CCalc1Dlg::On5()
{
if(m_output == "0")
{
m_output = "";
UpdateData(FALSE);
}
m_output += "5";
UpdateData(FALSE);
}
void CCalc1Dlg::On6()
{
if(m_output == "0")
{
m_output = "";
UpdateData(FALSE);
}
m_output += "6";
UpdateData(FALSE);
}
void CCalc1Dlg::On7()
{
if(m_output == "0")
{
m_output = "";
UpdateData(FALSE);
}
m_output += "7";
UpdateData(FALSE);
}
void CCalc1Dlg::On8()
{
if(m_output == "0")
{
m_output = "";
UpdateData(FALSE);
}
m_output += "8";
UpdateData(FALSE);
}
void CCalc1Dlg::On9()
{
if(m_output == "0")
{
m_output = "";
UpdateData(FALSE);
}
m_output += "9";
UpdateData(FALSE);
}
void CCalc1Dlg::On0()
{
if(m_output == "0")
{
m_output = "";
UpdateData(FALSE);
}
m_output += "0";
UpdateData(FALSE);
}
这里需要解释一下这段代码的含义如果不加这段代码,输入“1”,就会变成“01”,因为我们的m_output初始化为“0”,所以需要加个判断,如果我摁数字键的时候,输出框当前显示为“0”,则将输出框的字符串变量置为“空”。别忘了UpdateData数据!
3. 加减乘除,取余操作
void CCalc1Dlg::Onjia()
{
smallnum2 = "";
IsTemple = "jia";
num1 = m_output;
m_output = "";
m_out = num1+"+";
UpdateData(FALSE);
}
void CCalc1Dlg::Onjian()
{
smallnum2 = "";
IsTemple = "jian";
num1 = m_output;
m_output = "";
m_out = num1+"-";
UpdateData(FALSE);
}
void CCalc1Dlg::Oncheng()
{
smallnum2 = "";
IsTemple = "cheng";
num1 = m_output;
m_output = "";
m_out = num1+"×";
UpdateData(FALSE);
}
void CCalc1Dlg::Onchu()
{
smallnum2 = "";
IsTemple = "chu";
num1 = m_output;
m_output = "";
m_out = num1+"÷";
UpdateData(FALSE);
}
void CCalc1Dlg::Onquyu()
{
IsTemple = "quyu";
num1 = m_output;
m_output = "";
m_out = num1 + "%";
UpdateData(FALSE);
}
smallnum2和m_out的作用在下面讲,但是这里有必要说明的是整个代码的核心,IsTemple的作用。当我点“=”的时候,到底进行什么运算呢?这时IsTemple就派上用场了,没错,在“=”的函数里面加上判断,if(IsTemple ==“xxx”)的时候就执行什么运算。到了这里,你已经掌计算器的大部分核心代码了,接下来的就是增加一些计算器的细节代码。
4. 倒数,相反数,平方,立方,根号的操作
void CCalc1Dlg::Ondaoshu()
{
smallnum1 = "1";
double i;
num1 = m_output;
m_output = "";
UpdateData(FALSE);
if(num1 == "0")
{
m_output = "分母不能为0!";
UpdateData(FALSE);
m_output = "";
}
else
{
i = atof(num1);
m_output.Format("%lf",1/i);
UpdateData(FALSE);
}
}
void CCalc1Dlg::Onxiangfanshu()
{
smallnum2 = "";
if(smallnum1 == "1")
{
double i;
num1 = m_output;
m_output = "";
UpdateData(FALSE);
i = atof(num1);
m_output.Format("%lf",-i);
if(i<=0)
{
m_out = num1;
UpdateData(FALSE);
}
else
{
m_out = "-"+num1;
UpdateData(FALSE);
}
i = atof(num1);
UpdateData(FALSE);
}
else
{
int i;
num1 = m_output;
m_output = "";
UpdateData(FALSE);
i = atoi(num1);
m_output.Format("%d",-i);
UpdateData(FALSE);
}
}
void CCalc1Dlg::Onpingfang()
{
smallnum2 = "";
if(smallnum1 == "1")
{
double i;
num1 = m_output;
m_output = "";
UpdateData(FALSE);
i = atof(num1);
m_output.Format("%lf",i*i);
UpdateData(FALSE);
}
else
{
int i;
num1 = m_output;
m_output = "";
UpdateData(FALSE);
i = atoi(num1);
m_output.Format("%d",i*i);
UpdateData(FALSE);
}
}
void CCalc1Dlg::Onlifang()
{
smallnum2 = "";
if(smallnum1 == "1")
{
double i;
num1 = m_output;
m_output = "";
UpdateData(FALSE);
i = atof(num1);
m_output.Format("%lf",i*i*i);
UpdateData(FALSE);
}
else
{
int i;
num1 = m_output;
m_output = "";
UpdateData(FALSE);
i = atoi(num1);
m_output.Format("%d",i*i*i);
UpdateData(FALSE);
}
}
void CCalc1Dlg::Ongenhao()
{
smallnum2 = "";
double i;
num1 = m_output;
m_output = "";
UpdateData(FALSE);
i = atof(num1);
if(i<0)
{
m_output = "无效输入!";
UpdateData(FALSE);
m_output = "";
}
else
{
m_output.Format("%lf",sqrt(i));//别忘了添加个math.h头文件,这里我就不加了
UpdateData(FALSE);
}
}
为什么要把这几个代码和“加减乘除,取余”分开,是因为这几个代码不涉及到“等号”这个操作,用户输入的数,当他点击“倒数“,”相反数“,”平方“,”立方“,”根号”其中任意一个的时候,不需要点“等于”就可以产生结果了。这个逻辑要注意。
到这里为止,基本操作算是编写完成,接下来就开始实现这些操作,都在“等号”里面实现
—————————————————————————————————————————————————————
5. 等号的作用—>各个操作的实现
void CCalc1Dlg::Ondengyu()
{
if(IsTemple == "jia")
{
if(smallnum1 == "1")
{
double i,j,k;
num2 = m_output;
m_out += num2;
m_output = "";
UpdateData(FALSE);
i = atof(num1);
j = atof(num2);
k = i + j;
UpdateData(FALSE);
m_output.Format("%lf",k);
m_out += "="+m_output;
UpdateData(FALSE);
}
else
{
int i,j,k;
num2 = m_output;
m_output = "";
UpdateData(FALSE);
i = atoi(num1);
j = atoi(num2);
k = i + j;
UpdateData(FALSE);
m_output.Format("%d",k);
m_out += num2+"="+m_output;
UpdateData(FALSE);
}
}
if(IsTemple == "jian")
{
if(smallnum1 == "1")
{
double i,j,k;
num2 = m_output;
m_output = "";
UpdateData(FALSE);
i = atof(num1);
j = atof(num2);
k = i - j;
m_output.Format("%lf",k);
m_out += num2+"="+m_output;
UpdateData(FALSE);
}
else
{
int i,j,k;
num2 = m_output;
m_output = "";
UpdateData(FALSE);
i = atoi(num1);
j = atoi(num2);
k = i - j;
m_output.Format("%d",k);
m_out += num2+"="+m_output;
UpdateData(FALSE);
}
}
if(IsTemple == "cheng")
{
if(smallnum1 == "1")
{
double i,j,k;
num2 = m_output;
m_output = "";
UpdateData(FALSE);
i = atof(num1);
j = atof(num2);
k = i * j;
m_output.Format("%lf",k);
m_out += num2+"="+m_output;
UpdateData(FALSE);
}
else
{
int i,j,k;
num2 = m_output;
m_output = "";
UpdateData(FALSE);
i = atoi(num1);
j = atoi(num2);
k = i * j;
m_output.Format("%d",k);
m_out += num2+"="+m_output;
UpdateData(FALSE);
}
}
if(IsTemple == "chu")
{
if(m_output == "0")
{
m_output = "分母不能为0!";
UpdateData(FALSE);
m_output = "";
}
else
{
num2 = m_output;
m_output = "";
UpdateData(FALSE);
if(smallnum1 == "1")
{
CString n1 = num1;
CString n2 = num2;
double i,j,k;
i = atof(n1);
j = atof(n2);
k = i/j;
m_output.Format("%lf",k);
m_out += num2+"="+m_output;
UpdateData(FALSE);
}
else
{
CString n1 = num1;
CString n2 = num2;
int i,j;
i = atoi(n1);
j = atoi(n2);
if(i%j==0)
{
int k = i/j;
m_output.Format("%d",k);
m_out += num2+"="+m_output;
UpdateData(FALSE);
}
else
{
double s = atof(num1);
double x = atof(num2);
double k = s/x;
m_output.Format("%lf",k);
m_out += num2+"="+m_output;
UpdateData(FALSE);
}
}
}
}
if(IsTemple == "quyu")
{
if(num1!="")
{
int i,j,k;
num2 = m_output;
m_output = "";
UpdateData(FALSE);
i = atol(num1);
j = atol(num2);
k = i % j;
m_output.Format("%d",k);
m_out += num2+"="+m_output;
UpdateData(FALSE);
}
}
}
不要嫌代码长,先大概的看一遍,到这里读者应该发现了smallnum1的作用,当我点击“小数点”的时候,意味着有小数诞生了,这时我们就应该把操作全部变为“double”类型,而没点击“小数点”的时候,全是整数在进行运算,所以没必要定义为“double”类型,否则很不美观,所以定义为“int”类型。下面附上小数点的操作代码
void CCalc1Dlg::Ondian()
{
if((smallnum1!= "1"||smallnum2!= "1"))
{
smallnum1 = "1";
smallnum2 = "1";
m_output += ".";
UpdateData(FALSE);
}
}
至于为什么定义两个smallnum,这里就不解释了,读者可以思考一下,如果只定义一个smallnum会怎么样?这里还有一点要说的,if使用的很巧妙,如果不加if,直接m_output += “.”,用户就可以不停的点击“小数点”按钮,小数点就会不停的累加,这很不符合逻辑,对吧?
6. “CE,C和退格操作的实现”
在贴代码之前先给大家解释一下,计算器中CE的功能是什么。CE就是清除第二个操作数。举个简单的例子:我想计算15+5,但是我不小心点错了,点成了15+3,这个时候我还没点“=”,我点一下“CE”,那么计算器就会变为15+的状态,这时,我再点一下“5”,然后等于,就可以了。其他运算也相类似。下面附上代码
void CCalc1Dlg::Once()
{
smallnum1 = "";
smallnum2 = "";
num2 = "";
if(m_output != "0")
{
m_output = "0";
}
UpdateData(FALSE);
}
void CCalc1Dlg::Onc()
{
smallnum1 = "";
smallnum2 = "";
m_output = "0";
UpdateData(FALSE);
IsTemple = "";
}
void CCalc1Dlg::Onhuitui()
{
smallnum1 = "";
smallnum2 = "";
if(m_output != "0")
{
if(m_output.GetLength() == 1)
{
m_output = "0";
UpdateData(FALSE);
}
else
{
m_output = m_output.Left(m_output.GetLength()-1);
UpdateData(FALSE);
}
}
}
这部分代码没什么好说的,读者只要细心想想,当点击这些按钮的时候,什么应该清空,考虑周全就行。回退代码中可能这段代码读者额没见过,我稍微提一下m_output = m_output.Left(m_output.GetLength()-1);
,这其实是MFC库函数当中删掉字符串的函数,不理解的可以去百度或者看一下API文档,这里就不多解释了。
到现在为止,简易计算器的所有功能全部实现了,下面讲到的是如何将输入的数字以及进行的操作展示到“历史记录”面板,也很简单,读者如果有兴趣可以继续阅读。
—————————————————————————————————————————————————————
7. “历史纪录功能”
这里首先提醒读者一句,历史纪录我用的变量名叫m_out,”历史纪录“实现的代码其实和只是简单的赋值,穿插在前六点当中,读者重新阅读一遍便可发现,因为“倒数“,”相反数“,”平方“,”立方“,”根号”都不涉及“等号”操作,因此我没有设置这几个操作符保存历史纪录。
8. “结语”
因为作者英语水平有限,所以变量命名用的拼音,希望读者谅解。另外,计算器代码还有可以优化的地方,例如,小数去掉后面多余的0,这点读者暂时想不到,要是各位大佬有好想法可以私聊作者,QQ:739616037,同时,附上一篇修改exe文件图标的文章链接http://blog.sina.com.cn/s/blog_8216ada70101bteh.html,毕竟,默认的图标实在是太丑了。这是我更改后的图标 最后,感谢观看!