计算器的界面设计如上图所示
大致程序过程如下
按下数字键:
执行NumBottunDown( char num);
该函数会把按钮相对应的数字 (char num) 加入要显示的数字 (m_num) 中去
然后把运算符按下的标记置为false
按下运算符键:
执行OptBottunDown(char OprtCome);
该函数先做判断是否连续按下了运算符的按钮
如果是的,就不执行操作
如果不是,就先把运算符按下的标记置为true,然后将按出的数字压入数字栈,再进入OprtAction(OprtCome) 该函数会根据优先级来做相应操作,OprtAction 函数还会调用Calculation(double a, double b, char oprt) 来进行进一步的运算
完成运算后再进行一系列初始化
按下等号键:
执行MakeAnswer();
该函数会把最后的结果算出来同时会清除数据
按下正负键:
判断正负标志
标志为true,则删除m_num最前面的一个字符
标志为false,则在m_num的最前面加入负号
判断整除0的情况:
Calculation(double a, double b, char oprt) 这个函数当oprt为 除号的时候会做一次判断,看除数是否为0,若为0则将错误标志m_IsError置为 1
然后所有运算符按钮的函数在进入之后都会先做一个判断,看错误标志是否为0,如果不是0就进入ShowError()函数来显示错误
下面是代码:
头文件:
// CalculatorDlg.h: 头文件
//
#pragma once
#include <vector>
// CCalculatorDlg 对话框
class CCalculatorDlg : public CDialogEx
{
// 构造
public:
CCalculatorDlg(CWnd* pParent = nullptr); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_CALCULATOR_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CString NumBottunDown(char num);//按下数字
void OptBottunDown(char oprt); //按下运算符
void NumInStack(); //数字入栈
void OprtAction(char OprtCome); //运算符操作
void MakeAnswer(); //获取最后结果
double Calculation(double a, double b, char oprt);
int icp(char oprt); //栈外符号优先级
int isp(char oprt); //栈内符号优先级
void ShowError(); //显示错误
private:
CString m_display; //要显示的数
CString m_num; //按键产生的数
CString m_answer; //存储最后一次产生的结果,初值为0
bool m_IsDot; //是否按下小数点
bool m_IsNegative; //是否是负数
bool m_IsOprtBtnDown;//是否按下运算符,要初始化为true,目的是为了产生负数
std::vector<double> m_NumStack; //数字栈
std::vector<char> m_OprtStack; //符号栈
int m_IsError;//错误标志
public:
afx_msg void OnBnClickedButton1();
afx_msg void OnBnClickedButton2();
afx_msg void OnBnClickedButton3();
afx_msg void OnBnClickedButton4();
afx_msg void OnBnClickedButton5();
afx_msg void OnBnClickedButton6();
afx_msg void OnBnClickedButton7();
afx_msg void OnBnClickedButton8();
afx_msg void OnBnClickedButton9();
afx_msg void OnBnClickedButton0();
afx_msg void OnBnClickedButtondot();
afx_msg void OnBnClickedButtonadd();
afx_msg void OnBnClickedButtonsub();
afx_msg void OnBnClickedButtonmut();
afx_msg void OnBnClickedButtondiv();
afx_msg void OnBnClickedButtonequ();
afx_msg void OnBnClickedButtonallcln();
afx_msg void OnBnClickedButtoncln2();
afx_msg void OnBnClickedButtonneg();
};
源文件:
// CalculatorDlg.cpp: 实现文件
//
#include "stdafx.h"
#include "Calculator.h"
#include "CalculatorDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
//这里删除掉了系统自动上生成的 “关于” 对话框的实现
// CCalculatorDlg 对话框
CCalculatorDlg::CCalculatorDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_CALCULATOR_DIALOG, pParent)
, m_display("")
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
// m_NumStack.push_back(0);
m_OprtStack.push_back('#');
m_IsDot = false;
m_IsNegative = false;
m_IsOprtBtnDown = false;
m_IsError = 0;
}
void CCalculatorDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT1, m_display);
}
BEGIN_MESSAGE_MAP(CCalculatorDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, &CCalculatorDlg::OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON2, &CCalculatorDlg::OnBnClickedButton2)
ON_BN_CLICKED(IDC_BUTTON3, &CCalculatorDlg::OnBnClickedButton3)
ON_BN_CLICKED(IDC_BUTTON4, &CCalculatorDlg::OnBnClickedButton4)
ON_BN_CLICKED(IDC_BUTTON5, &CCalculatorDlg::OnBnClickedButton5)
ON_BN_CLICKED(IDC_BUTTON6, &CCalculatorDlg::OnBnClickedButton6)
ON_BN_CLICKED(IDC_BUTTON7, &CCalculatorDlg::OnBnClickedButton7)
ON_BN_CLICKED(IDC_BUTTON8, &CCalculatorDlg::OnBnClickedButton8)
ON_BN_CLICKED(IDC_BUTTON9, &CCalculatorDlg::OnBnClickedButton9)
ON_BN_CLICKED(IDC_BUTTON0, &CCalculatorDlg::OnBnClickedButton0)
ON_BN_CLICKED(IDC_BUTTONflag, &CCalculatorDlg::OnBnClickedButtondot)
ON_BN_CLICKED(IDC_BUTTONadd, &CCalculatorDlg::OnBnClickedButtonadd)
ON_BN_CLICKED(IDC_BUTTONmin, &CCalculatorDlg::OnBnClickedButtonsub)
ON_BN_CLICKED(IDC_BUTTONmut, &CCalculatorDlg::OnBnClickedButtonmut)
ON_BN_CLICKED(IDC_BUTTONdiv, &CCalculatorDlg::OnBnClickedButtondiv)
ON_BN_CLICKED(IDC_BUTTONequ, &CCalculatorDlg::OnBnClickedButtonequ)
ON_BN_CLICKED(IDC_BUTTONcln, &CCalculatorDlg::OnBnClickedButtonallcln)
ON_BN_CLICKED(IDC_BUTTONcln2, &CCalculatorDlg::OnBnClickedButtoncln2)
ON_BN_CLICKED(IDC_BUTTONneg, &CCalculatorDlg::OnBnClickedButtonneg)
END_MESSAGE_MAP()
// CCalculatorDlg 消息处理程序
BOOL CCalculatorDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
ShowWindow(SW_MINIMIZE);
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CCalculatorDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CCalculatorDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CCalculatorDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
CString CCalculatorDlg::NumBottunDown(char num)
{
m_IsOprtBtnDown = false;
return m_num += num;
}
void CCalculatorDlg::OptBottunDown(char OprtCome)
{
//若不是已经按下运算符按钮
if (!m_IsOprtBtnDown) {
NumInStack(); //将数字入栈
OprtAction(OprtCome); //根据操作符及其优先级选择操作
m_IsOprtBtnDown = true;
//把要显示的数初始化
m_IsNegative = false;
m_IsDot = false;
m_num = "";
}
}
void CCalculatorDlg::NumInStack()
{
double tmp;
if (!m_num.IsEmpty()) {
tmp = _wtof(m_num);
m_NumStack.push_back(tmp);
}
else {
tmp = _wtof(m_answer);
m_NumStack.push_back(tmp);
}
}
void CCalculatorDlg::OprtAction(char OprtCome)
{
//若优先级栈内大于栈外,且数字栈中有 2 个以上的数字,就进行运算
while (isp( m_OprtStack.back() ) > icp(OprtCome) && m_NumStack.size() >= 2)
{
double a, b;
//弹出两个数
b = m_NumStack.back();
m_NumStack.pop_back();
a = m_NumStack.back();
m_NumStack.pop_back();
//做计算然后将结果压入数字栈
m_NumStack.push_back(Calculation( a, b, m_OprtStack.back() ));
//符号弹出
m_OprtStack.pop_back();
}
//符号入栈
m_OprtStack.push_back(OprtCome);
}
void CCalculatorDlg::MakeAnswer()
{
m_answer.Format( _T("%g"), m_NumStack.back() ); //先存下结果
OnBnClickedButtonallcln(); //再清除数据
m_display = m_answer; //再显示数据
}
double CCalculatorDlg::Calculation(double a, double b, char oprt)
{
switch (oprt)
{
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/':
if (b == 0.0 && oprt == '/') {//出现除0
m_IsError = 1;
// m_OprtStack.push_back('#');
return 0;
}
return a / b;
default:
return 0;
break;
}
}
//in coming Priority
int CCalculatorDlg::icp(char oprt)
{
switch (oprt) {
case '*':
case '/': return 4;
case '+':
case '-': return 2;
case '(': return 6;
case ')': return 1;
default: return 0;
}
}
//in stack Priority
int CCalculatorDlg::isp(char oprt)
{
switch (oprt) {
case '*':
case '/': return 5;
case '+':
case '-': return 3;
case '(': return 1;
case ')': return 6;
default: return 0;
}
}
void CCalculatorDlg::ShowError()
{
switch (m_IsError)
{
case 1:
OnBnClickedButtonallcln();
m_display = "除数不能为0!";
break;
default:
break;
}
}
void CCalculatorDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
m_display = NumBottunDown('1');
UpdateData(FALSE);
}
void CCalculatorDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
m_display = NumBottunDown('2');
UpdateData(FALSE);
}
void CCalculatorDlg::OnBnClickedButton3()
{
// TODO: 在此添加控件通知处理程序代码
m_display = NumBottunDown('3');
UpdateData(FALSE);
}
void CCalculatorDlg::OnBnClickedButton4()
{
// TODO: 在此添加控件通知处理程序代码
m_display = NumBottunDown('4');
UpdateData(FALSE);
}
void CCalculatorDlg::OnBnClickedButton5()
{
// TODO: 在此添加控件通知处理程序代码
m_display = NumBottunDown('5');
UpdateData(FALSE);
}
void CCalculatorDlg::OnBnClickedButton6()
{
// TODO: 在此添加控件通知处理程序代码
m_display = NumBottunDown('6');
UpdateData(FALSE);
}
void CCalculatorDlg::OnBnClickedButton7()
{
// TODO: 在此添加控件通知处理程序代码
m_display = NumBottunDown('7');
UpdateData(FALSE);
}
void CCalculatorDlg::OnBnClickedButton8()
{
// TODO: 在此添加控件通知处理程序代码
m_display = NumBottunDown('8');
UpdateData(FALSE);
}
void CCalculatorDlg::OnBnClickedButton9()
{
// TODO: 在此添加控件通知处理程序代码
m_display = NumBottunDown('9');
UpdateData(FALSE);
}
void CCalculatorDlg::OnBnClickedButton0()
{
// TODO: 在此添加控件通知处理程序代码
m_display = NumBottunDown('0');
UpdateData(FALSE);
}
void CCalculatorDlg::OnBnClickedButtondot()
{
// TODO: 在此添加控件通知处理程序代码
if (!m_IsDot)
{
m_num += '.';
m_IsDot = true;
m_display = m_num;
UpdateData(FALSE);
}
}
//addition
void CCalculatorDlg::OnBnClickedButtonadd()
{
// TODO: 在此添加控件通知处理程序代码
OptBottunDown('+');
if (!m_IsError)
m_display.Format(_T("%g"), m_NumStack.back());//要更新显示最新的数据
else
ShowError();
UpdateData(FALSE);
}
//subtration
void CCalculatorDlg::OnBnClickedButtonsub()
{
// TODO: 在此添加控件通知处理程序代码
OptBottunDown('-');
if (!m_IsError)
m_display.Format(_T("%g"), m_NumStack.back());//要更新显示最新的数据
else
ShowError();
UpdateData(FALSE);
}
//mutiplication
void CCalculatorDlg::OnBnClickedButtonmut()
{
// TODO: 在此添加控件通知处理程序代码
OptBottunDown('*');
if (!m_IsError)
m_display.Format(_T("%g"), m_NumStack.back());//要更新显示最新的数据
else
ShowError();
UpdateData(FALSE);
}
//division
void CCalculatorDlg::OnBnClickedButtondiv()
{
// TODO: 在此添加控件通知处理程序代码
OptBottunDown('/');
if (!m_IsError)
m_display.Format(_T("%g"), m_NumStack.back());//要更新显示最新的数据
else
ShowError();
UpdateData(FALSE);
}
//equal
void CCalculatorDlg::OnBnClickedButtonequ()
{
// TODO: 在此添加控件通知处理程序代码
if (m_IsOprtBtnDown) m_OprtStack.pop_back();//如果多输入了一个运算符,将其去除
OptBottunDown('='); //获得最终结果
if (!m_IsError)
MakeAnswer(); //将最终结果保留自m_num中,并且要清除其他数据
else
ShowError();
UpdateData(FALSE);
}
//allclean
void CCalculatorDlg::OnBnClickedButtonallcln()
{
// TODO: 在此添加控件通知处理程序代码
m_display = "";
m_num = "";
if (!m_NumStack.empty()) m_NumStack.clear();
if (!m_OprtStack.empty()) m_OprtStack.clear();
m_NumStack.push_back(0);
m_OprtStack.push_back('#');
m_IsDot = false;
m_IsNegative = false;
m_IsOprtBtnDown = false;
m_IsError = 0;
UpdateData(FALSE);
}
//clean
void CCalculatorDlg::OnBnClickedButtoncln2()
{
// TODO: 在此添加控件通知处理程序代码
m_display = "";
m_num = "";
m_IsDot = false;
m_IsNegative = false;
// m_IsOprtBtnDown = false;
UpdateData(FALSE);
}
void CCalculatorDlg::OnBnClickedButtonneg()
{
// TODO: 在此添加控件通知处理程序代码
if (m_IsNegative)
{
m_IsNegative = !m_IsNegative;
m_num = m_num.Mid(1);
}
else
{
m_IsNegative = !m_IsNegative;
m_num = '-' + m_num;
}
m_display = m_num;
UpdateData(FALSE);
}