成果如下图:
视频演示效果可以关注微信公众号“艺千秋录”恢复“计算器”点击观看,同时还有更多功能实现的代码免费分享
具体实现步骤:
首先新建一个MFC应用项目并命名
选择基于对话框,单击完成
创建完成之后,进行对话框的搭建,首先在一下界面打开解决方案管理器---->选中资源文件打开箭头所指文档
将已有的一些控件选中删除
打开对话框旁边的工具栏---->将按钮控件和编辑框控件拖入对话框中
单击按钮直接在键盘上输入即可改变按钮名称
注意:双击按钮将会跳转到相应函数的实现
选中编辑框,添加两个变量,分别是控件变量m_edit和值变量m_str,操作一样
后面我们主要是对CString类型变量m_str进行操作,完成以上步骤,接下来我们就可以去实现各个控件的功能了,我们首先点击类视图---->打开头文件---->在类里面添加我们后续要用到的变量这些变量的功能我下面都给了注释
接下来我们可以回到对话框
双击一个你想要实现功能的Button控件进去它的实现函数,比如我们双击‘+’号控件,下面是对‘+’法按钮的实现
`//“加法”按键的实现
void CCalculateDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);//用来读取编辑框中的m_str内容
if (m_str.Right(1) != '(')//如果前面没有括号,则输入的是运算符,否则就是正号
{
savevalue1();//读取第一个操作数
if (c != '0')
calculate();
savevalue1();//读取第一个操作数
c = '+';
slength = m_str.GetLength() + 1;//后面会看到slength的用处
}
m_str = m_str + '+';
UpdateData(FALSE);//显示更新编辑框的内容,即将m_str的内容显示
}`
上面我们用savevalue1()函数从m_str变量中读取第一个操作数;
比如我们在编辑框中输入式子:“123 + 111” ,(此时编辑框关联的CString变量m_str=“123 + 111”),其实在我们点击‘+’号之前我们就已经进入了加法函数的实现,也就是说实现加法之前,m_str的内容还是“123”;
我们可以看到我们首先是利用savevalue1()为第一个操作数num1赋值为123并存储起来,功能的实现如下:
//保存第一个操作数据
void CCalculateDlg::savevalue1()
{
CString m_str1;
UpdateData(TRUE);//用来读取编辑框中的m_str内容
if (m_str[0] == '(')//如果第一个操作数用括号括起来了,则不读入括号
{
m_str1 = m_str.Right(m_str.GetLength() - 1);
m_str1 = m_str1.Left(m_str1.GetLength() - 1);
num1 = _ttof(m_str1);//将CString类型转换为double类型
}
else
num1 = _ttof(m_str);//将CString类型转换为double类型
UpdateData(FALSE);//显示更新编辑框的内容,即将m_str的内容显示
}
紧接着的是一个if语句,变量c是用来判断我们在点击‘+’号之前是否有点击过其它比如‘-’或‘*’等运算符,如果有点击过,m_str的内容应该会是这样“123 - 34 + 111”,这个时候它并不是一个操作数,而是一个式子,这个时候我们读取第一个操作数肯定会失败(有个‘-’号);
所以我们应该在读取第一个操作数之前,先将上面的式子预算一遍,并将变量m_str的内容更新为该式子的结果(此时为89 + 111),然后再读取第一个操作数(即89),再进行加法运算;
相信大家看到savevalue1()这个函数是还有一个问题,有一段关于是否有括号的if语句到底是什么意思?
其实这是后面我们实现时遇到的问题,比如当我们输入(-123)时,如果没有这段if语句,第一个操作数就会读取失败;
虽然一般没有人把第一个操作数括起来,但为了以防万一,我们可以避免这个问题;
这个时候我们已经完成了第一个操作数的读取,但是下一步我们又该怎么读取第二个操作数并实现加法这个功能呢?
其实我们读取第二个操作数是在运算函数calculate()里面实现的,具体内容如下:
void CCalculateDlg::calculate()
{
UpdateData(TRUE);
num2 = _ttof(m_str.Right(m_str.GetLength() - slength));//读取第二个操作数
double result = 0.0;
if (c == '+')
{
result = num1 + num2;
}
m_str.Format(TEXT("%f"), result);
c = '0';//表示默认无符号输入
UpdateData(FALSE);
}
//“等号”键实现
void CCalculateDlg::OnBnClickedButton6()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
if (c != '+' && c != '-' && c != '*' && c != '/'&& c != '!' && c != '^' && c -'0' > 9)
{
num1 = _ttof(m_str);
}
//当单击输入数值而没有单击操作符按钮、直接单击“=”时,界面上保持显示第一个操作数
else
calculate();
c = '0';//表示默认无符号输入
UpdateData(FALSE);
}
我们看到对于第二个操作数num2的读取,我们这里是利用了CString类型的一个函数Right(n),这个函数的功能就是读取字符串右边n个元素;
比如字符串为“123+111”时,我们使用m_str.Right(3),就会读取到字符串最右边三位元素(即111),所以我们就可以利用获取字符串字长的函数Getlength()以及变量slength来计算出第二个操作数占据字符串右边的位数;
以上述例子“123+111”,Getlength()会获取字符串长度为7,slength表示第二个操作数前面的字符串长度“123+”,此时slength=4,两数相减就可以得到第二个操作数的位数3了;
紧接着我们就可以对结果进行简单的加法运算了;
下面是关于“使用说明”、“退格”以及“清零”键的功能实现:
//“说明”按钮的实现
void CCalculateDlg::OnBnClickedButton5()
{
// TODO: 在此添加控件通知处理程序代码
MessageBox(TEXT("此计算器可以实现简单的加、减、乘、除等运算,对于操作数直接在键盘上输入即可,运算符请选择计算器中限定的运算符;\n注意事项:\n一、如果第二个操作数想输入负数,需在运算符后面将第二个数据括起来;\n二、对于正弦、余弦、正切、阶乘、开方等计算,请先按运算符按键,再输入角度值或数值,比如计算90度的正弦值:sin+90(非弧度制);\n三、对于“转为其它进制”的按键,这里只提供二进制(B)、八进制(O)以及十六进制(H)三种进制,输入其它进制均视为无效输入,输入格式为(需转换的数)->(进制基数)\n四、对于log对数的输入格式要求:先输入底数(非负数且不等于1)+log+真数(非负数);\n五、该计算器每次运算只支持两个操作数,如果想连续运算,可在结果后继续操作"),TEXT("使用说明"));
}
//“后退”键的实现
void CCalculateDlg::OnBnClickedButton8()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);//将屏幕中的数据转换到变量中
if (!m_str.IsEmpty())//如果字符串不为空
{
if (m_str.Right(1) == '*' || m_str.Right(1) == '+' || m_str.Right(1) == '-' || m_str.Right(1) == '/' || m_str.Right(1) == '^' || m_str.Right(1) == '!')
c = '0';
m_str = m_str.Left(m_str.GetLength() - 1);
}
UpdateData(FALSE);//将变量中的信息显示到相应的框中
}
//“清零”键的实现
void CCalculateDlg::OnBnClickedButton3()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
m_str = "";
UpdateData(FALSE);
}
其它功能的实现代码如下:
//各种运算符的实现
void CCalculateDlg::calculate()
{
UpdateData(TRUE);
num2 = _ttof(m_str.Right(m_str.GetLength() - slength));//读取第二个操作数
double result = 0.0;
if (c == '+')
{
result = num1 + num2;
}
else if (c == '-')
{
result = num1 - num2;
}
else if (c == '*')
{
result = num1 * num2;
}
else if (c == '/')
{
if (num2 == 0.0f)
{
MessageBox(TEXT("除数不能为0,请重新输入"));
}
else
{
result = num1 / num2;
}
}
else if (c == '^')//表示指数
{
result = pow(num1,num2);
}
else if (c == '!')//表示阶乘
{
result = 1.0;
for (long long i = 1; i <= long long(num1); i++)
result *= i;
}
else if (c == '1')//表示根号
{
result = sqrt(num1);
}
else if (c == '2')//表示sin
{
long long num = num2;
num %= 360;
num1 = num;
num1 = num1 / 180 * 3.1415926;
double item = num1;
result = num1;
long long i = 1;
do
{
item = -item * num1 * num1 / ((2 * i) * (2 * i + 1));
result += item;//sinx=x-x^3/3!+x^5/5!-x^7/7!+...
i++;
} while (fabs(item) >= 1e-5);//当精度达到10的五次方时跳出
}
else if (c == '3')//表示tan
{
long long num = num2;
num %= 180;
if (num == 90 || num == -90)//去除不再范围内的数
{
MessageBox(TEXT("此值不在正切函数的有效区域内,请重新输入"));
}
else
{
num1 = num;//将大度数化小
num1 = num1 / 180 * 3.1415926;//化为弧度制
result = tan(num1);
}
}
else if (c == '4')//表示cos
{
long long num = num2;
num %= 360;
num1 = num;
num1 = num1 / 180 * 3.1415926;
double item = 1;
result = 1;
long long i = 1;
do
{
item = -item * num1 * num1 / ((2 * i) * (2 * i - 1));
result += item;//cosx=1-x^2/2!+x^4/4!-x^6/6!+...
i++;
} while (fabs(item) >= 1e-5);//当精度达到10的五次方时跳出
}
else if (c == '5')//标志十进制转为其它进制
{
if (num2 == 2)//十进制转为二进制
{
CString test;//记录结果
long long T = num1;//记录整数部分
bool judge = true;//判断正负号,正为true,负为false
if (T < 0)
{
T = -T;
judge = false;
}
test.Format(TEXT("%lf"), num1);//将需要转化的十进制数变为字符串,方便取小数部分
double t;//记录小数部分
int pos = test.Find('.');
if (pos == -1)
t = 0;
else
{
test = test.Right(test.GetLength() - pos);//取小数部分字符串
t = _ttof(test);
}
test = "";//将字符串清空,方便后面记录二进制数
CString test1;
test1 = "";//记录余数,将余数反转即为二进制数
long long T1 = 0;
while (T)
{
test1 += char((T % 2) + 48);
T /= 2;
}
for (int i = test1.GetLength() - 1; i >= 0; i--)
test += test1[i];//反转余数排列
test += '.';//加入小数点
int len = test.GetLength()-1;
while (len <= 32)
{
t *= 2;
if (t >= 1)
{
test += '1';
t -= 1.0;
}
else
test += '0';
len++;
}
if (!judge)
m_str = '-' + test;
else
m_str = test;
m_str += "B";//表示二进制
return;
}
else if (num2 == 8)//转为八进制数
{
CString test;//记录结果
long long T = num1;//记录整数部分
bool judge = true;//判断正负号,正为true,负为false
if (T < 0)
{
T = -T;
judge = false;
}
test.Format(TEXT("%lf"), num1);//将需要转化的十进制数变为字符串,方便取小数部分
double t;//记录小数部分
int pos = test.Find('.');
if (pos == -1)
t = 0;
else
{
test = test.Right(test.GetLength() - pos);//取小数部分字符串
t = _ttof(test);
}
test = "";//将字符串清空,方便后面记录八进制数
CString test1;
test1 = "";//记录余数,将余数反转即为八进制数
long long T1 = 0;
while (T)
{
test1 += char((T % 8) + 48);
T /= 8;
}
for (int i = test1.GetLength() - 1; i >= 0; i--)
test += test1[i];//反转余数排列
test1 = "";//将字符串清零,用来记录小数部分的二进制数
test += '.';//加入小数点
int len = 3 * (test.GetLength() - 1);
while (len <= 32)//先将小数部分转化为二进制
{
t *= 2;
if (t >= 1)
{
test1 += '1';
t -= 1.0;
}
else
test1 += '0';
len++;
}
//将二进制小数转化为八进制
CString test2;//依次取前面三位数字转为八进制数
while (test1.GetLength() >= 3)
{
test2 = test1.Left(3);
test1 = test1.Right(test1.GetLength() - 3);//去掉前面已经遍历过的三位数字
int num = 0;
for (int i = 0; i < 3; i++)
{
if (test2[i] == '1')
{
num += pow(2, 2 - i);
}
}
test = test + char(num + 48);
}
if (!judge)
m_str = '-' + test;
else
m_str = test;
m_str += "o";//表示八进制
return;
}
else if(num2 == 16)
{
// MessageBox(TEXT("还未实现"));
CString test;//记录结果
char a[6] = { 'A','B','C','D','E','F' };//十六进制表示符
long long T = num1;//记录整数部分
bool judge = true;//判断正负号,正为true,负为false
if (T < 0)
{
T = -T;
judge = false;
}
test.Format(TEXT("%lf"), num1);//将需要转化的十进制数变为字符串,方便取小数部分
double t;//记录小数部分
int pos = test.Find('.');
if (pos == -1)
t = 0;
else
{
test = test.Right(test.GetLength() - pos);//取小数部分字符串
t = _ttof(test);
}
test = "";//将字符串清空,方便后面记录八进制数
CString test1;
test1 = "";//记录余数,将余数反转即为八进制数
long long T1 = 0;
while (T)
{
int z = T % 16;//记录余数
if (z < 10)
test1 += char(z + 48);
else
test1 += a[z - 10];
T /= 16;
}
for (int i = test1.GetLength() - 1; i >= 0; i--)
test += test1[i];//反转余数排列
test1 = "";//将字符串清零,用来记录小数部分的二进制数
test += '.';//加入小数点
int len = 4 * (test.GetLength() - 1);
while (len <= 32)//先将小数部分转化为二进制
{
t *= 2;
if (t >= 1)
{
test1 += '1';
t -= 1.0;
}
else
test1 += '0';
len++;
}
//将二进制小数转化为十六进制
CString test2;//依次取前面三位数字转为八进制数
while (test1.GetLength() >= 4)
{
test2 = test1.Left(4);
test1 = test1.Right(test1.GetLength() - 4);//去掉前面已经遍历过的四位数字
int num = 0;
for (int i = 0; i < 4; i++)
{
if (test2[i] == '1')
{
num += pow(2, 2 - i);
}
}
if (num < 10)
test = test + char(num + 48);
else
test = test + a[num - 10];
}
if (!judge)
m_str = '-' + test;
else
m_str = test;
m_str += "H";//表示十六进制
return;
}
else
{
MessageBox(TEXT("计算器不支持该进制,请重新输入(二进制或八进制或十六进制)"));
m_str = "";
return;
}
}
else if (c == '6')//转回十进制
{
m_str = m_str.Left(m_str.GetLength() - 4);
if (m_str.Right(1) != 'o' && m_str.Right(1) != 'H' && m_str.Right(1) != 'B')
{
return;
}
else
result = num1;
}
else if (c == '7')//表示对数log
{
if (num1 < 0 || num2 < 0 || num1 == 1)
{
MessageBox(TEXT("该对数无效,请重新输入!"));
m_str = "";
return;
}
else
result = log(num2) / log(num1);
}
else if (c == '8')//计算e^x
{
double item = 1;
result = 1;
int i = 1;
do
{
item = item * num2 / i;
i++;
result += item;
} while (fabs(item) > 1e-6);
}
m_str.Format(TEXT("%f"), result);
c = '0';//表示默认无符号输入
UpdateData(FALSE);
}
//“等号”键实现
void CCalculateDlg::OnBnClickedButton6()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
if (c != '+' && c != '-' && c != '*' && c != '/'&& c != '!' && c != '^' && c -'0' > 9)
{
num1 = _ttof(m_str);
}
//当单击输入数值而没有单击操作符按钮、直接单击“=”时,界面上保持显示第一个操作数
else
calculate();
c = '0';//表示默认无符号输入
UpdateData(FALSE);
}
//“加法”按键的实现
void CCalculateDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
if (m_str.Right(1) != '(')//如果前面没有括号,则输入的是运算符,否则就是正号
{
savevalue1();//读取第一个操作数
if (c != '0')
calculate();
savevalue1();//读取第一个操作数
c = '+';
slength = m_str.GetLength() + 1;
}
m_str = m_str + '+';
UpdateData(FALSE);
}
//“减法”键的实现
void CCalculateDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
if (m_str.Right(1) != '(')//如果前面没有括号,则输入的是运算符,否则就是负号
{
savevalue1();//读取第一个操作数
if (c != '0')
calculate();
savevalue1();//读取第一个操作数
c = '-';
slength = m_str.GetLength() + 1;
}
UpdateData(TRUE);
m_str = m_str + '-';
UpdateData(FALSE);
}
//“乘法”键的实现
void CCalculateDlg::OnBnClickedButton7()
{
// TODO: 在此添加控件通知处理程序代码
savevalue1();//读取第一个操作数
if (c != '0')
calculate();
savevalue1();//读取第一个操作数
slength = m_str.GetLength() + 1;
UpdateData(TRUE);
m_str = m_str + '*';
UpdateData(FALSE);
c = '*';
}
//“除法”键的实现
void CCalculateDlg::OnBnClickedButton4()
{
// TODO: 在此添加控件通知处理程序代码
savevalue1();//读取第一个操作数
if (c != '0')
calculate();
savevalue1();//读取第一个操作数
slength = m_str.GetLength() + 1;
UpdateData(TRUE);
m_str = m_str + '/';
UpdateData(FALSE);
c = '/';
}
//“指数”运算符的实现
void CCalculateDlg::OnBnClickedButton25()
{
// TODO: 在此添加控件通知处理程序代码
savevalue1();//读取第一个操作数
if (c != '0')
calculate();
savevalue1();//读取第一个操作数
slength = m_str.GetLength() + 1;
UpdateData(TRUE);
m_str = m_str + '^';
UpdateData(FALSE);
c = '^';
}
//“阶乘”运算符的实现
void CCalculateDlg::OnBnClickedButton27()
{
// TODO: 在此添加控件通知处理程序代码
savevalue1();//读取第一个操作数
if (c != '0')
calculate();
savevalue1();//读取第一个操作数
UpdateData(TRUE);
m_str = m_str + '!';
UpdateData(FALSE);
c = '!';
}
//“根号”运算符的实现
void CCalculateDlg::OnBnClickedButton26()
{
// TODO: 在此添加控件通知处理程序代码
savevalue1();//读取第一个操作数
if (c != '0')
calculate();
savevalue1();//读取第一个操作数
UpdateData(TRUE);
UpdateData(FALSE);
c = '1';//用1标志根号运算符
calculate();
}
//“sin正弦”运算符的实现
void CCalculateDlg::OnBnClickedButton22()
{
// TODO: 在此添加控件通知处理程序代码
savevalue1();//读取第一个操作数
slength = m_str.GetLength() + 3;
UpdateData(TRUE);
m_str = CString("sin");
UpdateData(FALSE);
c = '2';//用2标志sin运算符
//calculate();
}
//“tan正切”运算符的实现
void CCalculateDlg::OnBnClickedButton24()
{
// TODO: 在此添加控件通知处理程序代码
savevalue1();//读取第一个操作数
slength = m_str.GetLength() + 3;
UpdateData(TRUE);
m_str = CString("tan");
UpdateData(FALSE);
c = '3';//用3标志tan运算符
//calculate();
}
//“cos余弦”运算符的实现
void CCalculateDlg::OnBnClickedButton23()
{
// TODO: 在此添加控件通知处理程序代码
savevalue1();//读取第一个操作数
slength = m_str.GetLength() + 3;
UpdateData(TRUE);
m_str = CString("cos");
UpdateData(FALSE);
c = '4';//用4标志cos运算符
//calculate();
}
//“进制”的转换
void CCalculateDlg::OnBnClickedButton29()
{
// TODO: 在此添加控件通知处理程序代码
savevalue1();//读取第一个操作数
slength = m_str.GetLength() + 2;
UpdateData(TRUE);
m_str += "->";
UpdateData(FALSE);
c = '5';//用5标志进制运算符
}
//“对数”的运算
void CCalculateDlg::OnBnClickedButton28()
{
// TODO: 在此添加控件通知处理程序代码
savevalue1();//读取第一个操作数
slength = m_str.GetLength() + 5;
UpdateData(TRUE);
m_str = CString("log(") + m_str + ')';
UpdateData(FALSE);
c = '7';
}
//“回到十进制”将其它进制数转回十进制
void CCalculateDlg::OnBnClickedButton31()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
m_str += "->10";
UpdateData(FALSE);
c = '6';//用6标志十进制运算符
}
//“e^x”的次方的计算
void CCalculateDlg::OnBnClickedButton30()
{
// TODO: 在此添加控件通知处理程序代码
savevalue1();//读取第一个操作数
slength = m_str.GetLength() + 2;
UpdateData(TRUE);
m_str = CString("e^") + m_str;
UpdateData(FALSE);
c = '8';//用8标志e^x运算符
}
//“括号”键的实现
void CCalculateDlg::OnBnClickedButton20()
{
// TODO: 在此添加控件通知处理程序代码
savevalue1();//读取第一个操作数
slength = m_str.GetLength() + 1;
m_str = m_str + '(';
UpdateData(FALSE);
}
void CCalculateDlg::OnBnClickedButton21()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
if(c=='0')//如果前面没有运算符表示是第一个操作数被括起来了
slength = m_str.GetLength() + 1;
m_str = m_str + ')';
UpdateData(FALSE);
}
void CCalculateDlg::OnBnClickedButton9()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
m_str = m_str + '1';
UpdateData(FALSE);
}
void CCalculateDlg::OnBnClickedButton12()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
m_str = m_str + '2';
UpdateData(FALSE);
}
void CCalculateDlg::OnBnClickedButton13()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
m_str = m_str + '3';
UpdateData(FALSE);
}
void CCalculateDlg::OnBnClickedButton10()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
m_str = m_str + '4';
UpdateData(FALSE);
}
void CCalculateDlg::OnBnClickedButton11()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
m_str = m_str + '5';
UpdateData(FALSE);
}
void CCalculateDlg::OnBnClickedButton16()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
m_str = m_str + '6';
UpdateData(FALSE);
}
void CCalculateDlg::OnBnClickedButton14()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
m_str = m_str + '7';
UpdateData(FALSE);
}
void CCalculateDlg::OnBnClickedButton17()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
m_str = m_str + '8';
UpdateData(FALSE);
}
void CCalculateDlg::OnBnClickedButton15()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
m_str = m_str + '9';
UpdateData(FALSE);
}
void CCalculateDlg::OnBnClickedButton18()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
m_str = m_str + '0';
UpdateData(FALSE);
}
void CCalculateDlg::OnBnClickedButton19()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
m_str = m_str + '.';
UpdateData(FALSE);
}
本人能力有限,有不足之处请谅解并欢迎指出;如果文章对您有帮助的话,别忘了点赞收藏支持一下作者(感谢您的鼓励);
更多功能的代码实现请微信关注公众号“艺千秋录”,回复“计算器”即可查看