加载中...

MFC简易计算器的实现

MFC简易计算器的实现

1 概述

1.1 第一步

添加组件 界面布局:根据所要的需求+-*/,四则运算,科学运算等,设计一下布局

1.2 第二步

给各个组件 按钮和文本框添加函数:设置它的相应函数

1.3 第三步

测试:看看有没有问题

2 第一步 添加组件 界面布局


实际上,0、1、2、3并没有全都用到,只用了1 HuangPengcalculator.rc和3 HuangPengcalculator.cpp这两个也可以实现简易的计算器

2.1 HuangPengcalculatorapp.rc

先设置界面布局,添加组件,所添加的组件都会在Resource.h里面自动生成


按住Ctrl可以多选,进行多个组件的复制操作

对各个组件进行相应设计,得到最终的界面布局


2.2 描述文字 ID

在属性列表里面,对各个组件(按钮和文本框)进行命名(描述文字),并按顺序、条理修改对应的ID,以免出现混乱对应不上的问题



所定义的这些按钮以及编辑框就都会出现在Resource.h里面

3 第二步 给各个组件 按钮和文本框添加函数

3.1 依次双击控件按钮和两个编辑框

依次(Button1到Button19)双击控件按钮和两个编辑框,会在“计算器Dlg.cpp”生成代码 ,到时候控件响应事件就是在这里做的(推荐将除了数字以外的按钮的ID改成英文来区别,如乘法:ButtonMut)


要对哪个组件 按钮和文本框添加函数只需要双击这个组件(按钮或文本框),便可快速进入到.cpp的相应函数位置,然后对这个函数进行具体的实现,即可完成该组件(按钮或文本框)的函数添加

3.2 对两编辑框添加变量

右键第一个编辑框选择添加变量,添加一个value的CString类型的变量mStr,这个变量绑定了编辑框1,我们就通过操作这个变量来实现按钮响应的可视化,就是说输入哪一个数字都会显示在第一个编辑框内。


第二个edit,我们需要右键添加变量,给他绑定一个private的vlaue的double的mResult,这个是用来接收结果的,因此第二个编辑框也就是用来显示结果的。


3.3 按钮添加响应事件

进入计算器Dlg.cpp(你自己的工程叫XXX就是XXXDlg.cpp),为按钮添加响应事件,代码如下。

void CHuangPengcalculatorDlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr+L"1";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}

添加完后就可以调试运行一下了,写程序我们要学会调试,调试的过程中寻求反馈,菜鸟程序员不要一码到底不然很容易对编程失去兴趣。(毛主席说过,越是困难的时候越是要看到光明,大概就是这个意思吧)

接下来将其他同类型的按钮也添加响应事件,包括Button2-Button11如下面代码所示:

void CHuangPengcalculatorDlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr+L"1";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton2()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"2";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton3()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"3";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton4()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"4";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton5()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"5";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton6()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"6";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton7()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"7";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton8()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"8";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton9()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"9";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton0()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"0";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}

3.4 在Dlg.h里面添加一些变量和函数

我们要在"计算器Dlg.h"(XXXDlg.h)里面添加一些变量和函数,代码如下:

/*这两个函数都要在Dlg.cpp里面重写*/
	void SaveFirstValue();//这个是用来保存一个输入完成的值的
	void Calculator();//这个是用来实现计算的

private:
	double mNum1;//第一个值
	double mNum2;//第二个值
	int mFlag;//传递运算符,来触发switch中的事件
	CString mStr;//这个是edit1绑定的值,字符串类型,不用自己手动定义
	double mResult;//这个是edit2绑定的值,double型,不用手动定义

转到“计算器Dlg.cpp”重写上面两个关键函数,在程序末尾写:

void CHuangPengcalculatorDlg::SaveFirstValue()
{
	UpdateData(TRUE);//刷新应用状态

	mNum1 = _wtof(mStr);//“_wtof”可以将CString转换成double型
	mStr = L"";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::Calculator()
{
	UpdateData(TRUE);
	mNum2 = _wtof(mStr);
	switch (mFlag)//按接收键传过来的mFlag的值,以此来判断是什么运算符
	{
	case 1:
		mResult = mNum1 + mNum2;
		break;
	case 2:
		mResult = mNum1 - mNum2;
		break;
	case 3:
		mResult = mNum1 * mNum2;
		break;
	case 4:
		mResult = mNum1 / mNum2;
		break;
	case 5:
		mResult = pow(mNum1, mNum2);
		break;
	case 6:
		{
			if (mNum1 < 0 || mNum2 < 0 || mNum1 == 1)
			{
				MessageBox(TEXT("该对数无效,请重新输入!"));
				mStr = "";
				return;
			}
			else
				mResult = log(mNum2) / log(mNum1);
			break;
		}
	case 7:
		{
			double item = 1;
			mResult = 1;
			int i = 1;
			do
			{
				item = item * mNum2 / i;
				i++;
				mResult += item;
			} while (fabs(item) > 1e-6);
			break;
		}
	case 8:
		{
			mResult = 1.0;
			for (long long i = 1; i <= long long(mNum1); i++)
				mResult *= i;
			break;
		}
	case 9:
		{
			long long num = mNum2;
			num %= 360;
			mNum1 = num;
			mNum1 = mNum1 / 180 * 3.1415926;
			double item = mNum1;
			mResult = mNum1;
			long long i = 1;
			do
			{
				item = -item * mNum1 * mNum1 / ((2 * i) * (2 * i + 1));
				mResult += item;//sinx=x-x^3/3!+x^5/5!-x^7/7!+...
				i++;
			} while (fabs(item) >= 1e-5);//当精度达到10的五次方时跳出
			break;
		}
	case 10:
		{
			long long num = mNum2;
			num %= 360;
			mNum1 = num;
			mNum1 = mNum1 / 180 * 3.1415926;
			double item = 1;
			mResult = 1;
			long long i = 1;
			do
			{
				item = -item * mNum1 * mNum1 / ((2 * i) * (2 * i - 1));
				mResult += item;//cosx=1-x^2/2!+x^4/4!-x^6/6!+...
				i++;
			} while (fabs(item) >= 1e-5);//当精度达到10的五次方时跳出
			break;
		}
	case 11:
		{
			long long num = mNum2;
			num %= 180;
			if (num == 90 || num == -90)//去除不再范围内的数
			{
				MessageBox(TEXT("此值不在正切函数的有效区域内,请重新输入"));
			}
			else
			{
				mNum1 = num;//将大度数化小
				mNum1 = mNum1 / 180 * 3.1415926;//化为弧度制
				mResult = tan(mNum1);
			}
			break;
		}
	case 12:
		mResult = sqrt(mNum1);
		break;
	}
	UpdateData(FALSE);
}

同样是在“计算器Dlg.cpp”下一步将添加运算符响应事件,添加在数字按钮后最好:(顺序为等于、加、减、乘、除):

void CHuangPengcalculatorDlg::OnBnClickedButtonjia()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 1;//加法的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonjian()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 2;//减法的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtoncheng()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 3;//乘法的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonchu()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 4;//除法的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonpoint()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L".";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButtoncifang()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 5;//指数(次方)的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonlognx()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 6;//对数lognx的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonex()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 7;//e^x的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonx()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 8;//x!的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonsin()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 9;//sin的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtoncos()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 10;//cos的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtontan()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 11;//tan的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonsqrt()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 12;//开方的功能
}

3.5 添加"清除"、“删除”、“退出”

还是在“计算器Dlg.cpp”

void CHuangPengcalculatorDlg::OnBnClickedButtonback()//删除最后一个数字
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(FALSE);//将数据更新到控件
	if (!mStr.IsEmpty())
	{
		mStr = mStr.Left(mStr.GetLength() - 1);//删除最右边一位
	}
	UpdateData(FALSE);//将数据更新到控件

}


void CHuangPengcalculatorDlg::OnBnClickedButtonclear()//清除键,归零键
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	mStr = L"0";//字符串前加L就是把数据转换成Unicode格式
	mResult = 0.0;
	mNum1 = 0.0f;
	mNum2 = 0.0f;
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButtonexit()//退出软件
{
	// TODO: 在此添加控件通知处理程序代码
	exit(0);
}

3.6 添加支持键盘操作的功能

描述:可以通过小键盘来用计算器,按回车键计算结果,按Backspace删除最后一位数字。

右键单击对话框,选择添加“类向导”,选择“虚函数”,选择下面这个函数,双击它,应用。


然后返回到“计算器Dlg.cpp”找到刚刚添加的类,在里面添加键盘按键响应事件。

BOOL CHuangPengcalculatorDlg::PreTranslateMessage(MSG* pMsg)//支持键盘操作
{
	// TODO: 在此添加专用代码和/或调用基类
	if (pMsg->message == WM_KEYDOWN)
	{
		if (pMsg->wParam == VK_RETURN)//回车键
		{
			Calculator();
		}
		if (pMsg->wParam == VK_BACK)//删除键
		{
			CHuangPengcalculatorDlg::OnBnClickedButtonback();

		}
		if (pMsg->wParam == VK_ADD)//加法键
		{
			CHuangPengcalculatorDlg::OnBnClickedButtonjia();

		}

		if (pMsg->wParam == VK_SUBTRACT)//减法键
		{
			CHuangPengcalculatorDlg::OnBnClickedButtonjian();

		}
		if (pMsg->wParam == VK_MULTIPLY)//乘法键
		{
			CHuangPengcalculatorDlg::OnBnClickedButtoncheng();

		}
		if (pMsg->wParam == VK_DIVIDE)//除法键
		{
			CHuangPengcalculatorDlg::OnBnClickedButtonchu();

		}

	}
	if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) return TRUE;//屏蔽esc键
	if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) return TRUE;//屏蔽回车键,让他不再退出
	else


	return CDialogEx::PreTranslateMessage(pMsg);
}

在属性页将edit1设置成只能输入数字


将edit2设置成只读


运行成功!你可以在工程文件的Debug目录下找到“.exe”文件。

4 第三步 测试:看看有没有问题

整个MFC简易计算器的代码如下:

4.1 Dlg.h


// HuangPengcalculatorDlg.h: 头文件
//

#pragma once


// CHuangPengcalculatorDlg 对话框
class CHuangPengcalculatorDlg : public CDialogEx
{
// 构造
public:
	CHuangPengcalculatorDlg(CWnd* pParent = nullptr);	// 标准构造函数

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_HUANGPENGCALCULATOR_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:
	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 OnBnClickedButtonjia();
	afx_msg void OnBnClickedButtonjian();
	afx_msg void OnBnClickedButtoncheng();
	afx_msg void OnBnClickedButtonchu();
	afx_msg void OnBnClickedButtonpoint();
	afx_msg void OnBnClickedButtoncifang();
	afx_msg void OnBnClickedButtonlognx();
	afx_msg void OnBnClickedButtonex();
	afx_msg void OnBnClickedButtonx();
	afx_msg void OnBnClickedButtonsin();
	afx_msg void OnBnClickedButtoncos();
	afx_msg void OnBnClickedButtontan();
	afx_msg void OnBnClickedButtonsqrt();
	afx_msg void OnBnClickedButtonequal();
	afx_msg void OnBnClickedButtonback();
	afx_msg void OnBnClickedButtonclear();
	afx_msg void OnEnChangeEdit1();
	afx_msg void OnEnChangeEdit2();

	/*这两个函数都要在Dlg.cpp里面重写*/
	void SaveFirstValue();//这个是用来保存一个输入完成的值的
	void Calculator();//这个是用来实现计算的

private:
	double mNum1;//第一个值
	double mNum2;//第二个值
	int mFlag;//传递运算符,来触发switch中的事件
	CString mStr;//这个是edit1绑定的值,字符串类型,不用自己手动定义
	double mResult;//这个是edit2绑定的值,double型,不用手动定义
public:
	afx_msg void OnBnClickedButtonexit();
	virtual BOOL PreTranslateMessage(MSG* pMsg);
};



4.2 Dlg.cpp


// HuangPengcalculatorDlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "HuangPengcalculator.h"
#include "HuangPengcalculatorDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CHuangPengcalculatorDlg 对话框



CHuangPengcalculatorDlg::CHuangPengcalculatorDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_HUANGPENGCALCULATOR_DIALOG, pParent)
	, mStr(_T(""))
	, mResult(0)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CHuangPengcalculatorDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Text(pDX, IDC_EDIT1, mStr);
	DDX_Text(pDX, IDC_EDIT2, mResult);
}

BEGIN_MESSAGE_MAP(CHuangPengcalculatorDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, &CHuangPengcalculatorDlg::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON2, &CHuangPengcalculatorDlg::OnBnClickedButton2)
	ON_BN_CLICKED(IDC_BUTTON3, &CHuangPengcalculatorDlg::OnBnClickedButton3)
	ON_BN_CLICKED(IDC_BUTTON4, &CHuangPengcalculatorDlg::OnBnClickedButton4)
	ON_BN_CLICKED(IDC_BUTTON5, &CHuangPengcalculatorDlg::OnBnClickedButton5)
	ON_BN_CLICKED(IDC_BUTTON6, &CHuangPengcalculatorDlg::OnBnClickedButton6)
	ON_BN_CLICKED(IDC_BUTTON7, &CHuangPengcalculatorDlg::OnBnClickedButton7)
	ON_BN_CLICKED(IDC_BUTTON8, &CHuangPengcalculatorDlg::OnBnClickedButton8)
	ON_BN_CLICKED(IDC_BUTTON9, &CHuangPengcalculatorDlg::OnBnClickedButton9)
	ON_BN_CLICKED(IDC_BUTTON0, &CHuangPengcalculatorDlg::OnBnClickedButton0)
	ON_BN_CLICKED(IDC_BUTTONJIA, &CHuangPengcalculatorDlg::OnBnClickedButtonjia)
	ON_BN_CLICKED(IDC_BUTTONJIAN, &CHuangPengcalculatorDlg::OnBnClickedButtonjian)
	ON_BN_CLICKED(IDC_BUTTONCHENG, &CHuangPengcalculatorDlg::OnBnClickedButtoncheng)
	ON_BN_CLICKED(IDC_BUTTONCHU, &CHuangPengcalculatorDlg::OnBnClickedButtonchu)
	ON_BN_CLICKED(IDC_BUTTONPOINT, &CHuangPengcalculatorDlg::OnBnClickedButtonpoint)
	ON_BN_CLICKED(IDC_BUTTONCIFANG, &CHuangPengcalculatorDlg::OnBnClickedButtoncifang)
	ON_BN_CLICKED(IDC_BUTTONLOGNX, &CHuangPengcalculatorDlg::OnBnClickedButtonlognx)
	ON_BN_CLICKED(IDC_BUTTONEX, &CHuangPengcalculatorDlg::OnBnClickedButtonex)
	ON_BN_CLICKED(IDC_BUTTONX, &CHuangPengcalculatorDlg::OnBnClickedButtonx)
	ON_BN_CLICKED(IDC_BUTTONSIN, &CHuangPengcalculatorDlg::OnBnClickedButtonsin)
	ON_BN_CLICKED(IDC_BUTTONCOS, &CHuangPengcalculatorDlg::OnBnClickedButtoncos)
	ON_BN_CLICKED(IDC_BUTTONTAN, &CHuangPengcalculatorDlg::OnBnClickedButtontan)
	ON_BN_CLICKED(IDC_BUTTONSQRT, &CHuangPengcalculatorDlg::OnBnClickedButtonsqrt)
	ON_BN_CLICKED(IDC_BUTTONEQUAL, &CHuangPengcalculatorDlg::OnBnClickedButtonequal)
	ON_BN_CLICKED(IDC_BUTTONBACK, &CHuangPengcalculatorDlg::OnBnClickedButtonback)
	ON_BN_CLICKED(IDC_BUTTONCLEAR, &CHuangPengcalculatorDlg::OnBnClickedButtonclear)
	ON_EN_CHANGE(IDC_EDIT1, &CHuangPengcalculatorDlg::OnEnChangeEdit1)
	ON_EN_CHANGE(IDC_EDIT2, &CHuangPengcalculatorDlg::OnEnChangeEdit2)
	ON_BN_CLICKED(IDC_BUTTONEXIT, &CHuangPengcalculatorDlg::OnBnClickedButtonexit)
END_MESSAGE_MAP()


// CHuangPengcalculatorDlg 消息处理程序

BOOL CHuangPengcalculatorDlg::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);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CHuangPengcalculatorDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CHuangPengcalculatorDlg::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 CHuangPengcalculatorDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



void CHuangPengcalculatorDlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr+L"1";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton2()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"2";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton3()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"3";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton4()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"4";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton5()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"5";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton6()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"6";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton7()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"7";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton8()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"8";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton9()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"9";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButton0()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L"0";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButtonjia()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 1;//加法的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonjian()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 2;//减法的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtoncheng()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 3;//乘法的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonchu()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 4;//除法的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonpoint()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//刷新应用状态
	mStr = mStr + L".";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButtoncifang()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 5;//指数(次方)的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonlognx()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 6;//对数lognx的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonex()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 7;//e^x的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonx()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 8;//x!的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonsin()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 9;//sin的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtoncos()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 10;//cos的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtontan()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 11;//tan的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonsqrt()
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	mFlag = 12;//开方的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonequal()
{
	// TODO: 在此添加控件通知处理程序代码
	Calculator();//等于号的功能
}


void CHuangPengcalculatorDlg::OnBnClickedButtonback()//删除最后一个数字
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(FALSE);//将数据更新到控件
	if (!mStr.IsEmpty())
	{
		mStr = mStr.Left(mStr.GetLength() - 1);//删除最右边一位
	}
	UpdateData(FALSE);//将数据更新到控件

}


void CHuangPengcalculatorDlg::OnBnClickedButtonclear()//清除键,归零键
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	mStr = L"0";//字符串前加L就是把数据转换成Unicode格式
	mResult = 0.0;
	mNum1 = 0.0f;
	mNum2 = 0.0f;
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::OnBnClickedButtonexit()//退出软件
{
	// TODO: 在此添加控件通知处理程序代码
	exit(0);
}


void CHuangPengcalculatorDlg::OnEnChangeEdit1()
{
	// TODO:  如果该控件是 RICHEDIT 控件,它将不
	// 发送此通知,除非重写 CDialogEx::OnInitDialog()
	// 函数并调用 CRichEditCtrl().SetEventMask(),
	// 同时将 ENM_CHANGE 标志“或”运算到掩码中。

	// TODO:  在此添加控件通知处理程序代码
}


void CHuangPengcalculatorDlg::OnEnChangeEdit2()
{
	// TODO:  如果该控件是 RICHEDIT 控件,它将不
	// 发送此通知,除非重写 CDialogEx::OnInitDialog()
	// 函数并调用 CRichEditCtrl().SetEventMask(),
	// 同时将 ENM_CHANGE 标志“或”运算到掩码中。

	// TODO:  在此添加控件通知处理程序代码
}


void CHuangPengcalculatorDlg::SaveFirstValue()
{
	UpdateData(TRUE);//刷新应用状态

	mNum1 = _wtof(mStr);//“_wtof”可以将CString转换成double型
	mStr = L"";//字符前加L是把字符转换成Unicode型
	UpdateData(FALSE);
}


void CHuangPengcalculatorDlg::Calculator()
{
	UpdateData(TRUE);
	mNum2 = _wtof(mStr);
	switch (mFlag)//按接收键传过来的mFlag的值,以此来判断是什么运算符
	{
	case 1:
		mResult = mNum1 + mNum2;
		break;
	case 2:
		mResult = mNum1 - mNum2;
		break;
	case 3:
		mResult = mNum1 * mNum2;
		break;
	case 4:
		mResult = mNum1 / mNum2;
		break;
	case 5:
		mResult = pow(mNum1, mNum2);
		break;
	case 6:
		{
			if (mNum1 < 0 || mNum2 < 0 || mNum1 == 1)
			{
				MessageBox(TEXT("该对数无效,请重新输入!"));
				mStr = "";
				return;
			}
			else
				mResult = log(mNum2) / log(mNum1);
			break;
		}
	case 7:
		{
			double item = 1;
			mResult = 1;
			int i = 1;
			do
			{
				item = item * mNum2 / i;
				i++;
				mResult += item;
			} while (fabs(item) > 1e-6);
			break;
		}
	case 8:
		{
			mResult = 1.0;
			for (long long i = 1; i <= long long(mNum1); i++)
				mResult *= i;
			break;
		}
	case 9:
		{
			long long num = mNum2;
			num %= 360;
			mNum1 = num;
			mNum1 = mNum1 / 180 * 3.1415926;
			double item = mNum1;
			mResult = mNum1;
			long long i = 1;
			do
			{
				item = -item * mNum1 * mNum1 / ((2 * i) * (2 * i + 1));
				mResult += item;//sinx=x-x^3/3!+x^5/5!-x^7/7!+...
				i++;
			} while (fabs(item) >= 1e-5);//当精度达到10的五次方时跳出
			break;
		}
	case 10:
		{
			long long num = mNum2;
			num %= 360;
			mNum1 = num;
			mNum1 = mNum1 / 180 * 3.1415926;
			double item = 1;
			mResult = 1;
			long long i = 1;
			do
			{
				item = -item * mNum1 * mNum1 / ((2 * i) * (2 * i - 1));
				mResult += item;//cosx=1-x^2/2!+x^4/4!-x^6/6!+...
				i++;
			} while (fabs(item) >= 1e-5);//当精度达到10的五次方时跳出
			break;
		}
	case 11:
		{
			long long num = mNum2;
			num %= 180;
			if (num == 90 || num == -90)//去除不再范围内的数
			{
				MessageBox(TEXT("此值不在正切函数的有效区域内,请重新输入"));
			}
			else
			{
				mNum1 = num;//将大度数化小
				mNum1 = mNum1 / 180 * 3.1415926;//化为弧度制
				mResult = tan(mNum1);
			}
			break;
		}
	case 12:
		mResult = sqrt(mNum1);
		break;
	}
	UpdateData(FALSE);
}


BOOL CHuangPengcalculatorDlg::PreTranslateMessage(MSG* pMsg)//支持键盘操作
{
	// TODO: 在此添加专用代码和/或调用基类
	if (pMsg->message == WM_KEYDOWN)
	{
		if (pMsg->wParam == VK_RETURN)//回车键
		{
			Calculator();
		}
		if (pMsg->wParam == VK_BACK)//删除键
		{
			CHuangPengcalculatorDlg::OnBnClickedButtonback();

		}
		if (pMsg->wParam == VK_ADD)//加法键
		{
			CHuangPengcalculatorDlg::OnBnClickedButtonjia();

		}

		if (pMsg->wParam == VK_SUBTRACT)//减法键
		{
			CHuangPengcalculatorDlg::OnBnClickedButtonjian();

		}
		if (pMsg->wParam == VK_MULTIPLY)//乘法键
		{
			CHuangPengcalculatorDlg::OnBnClickedButtoncheng();

		}
		if (pMsg->wParam == VK_DIVIDE)//除法键
		{
			CHuangPengcalculatorDlg::OnBnClickedButtonchu();

		}

	}
	if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) return TRUE;//屏蔽esc键
	if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) return TRUE;//屏蔽回车键,让他不再退出
	else


	return CDialogEx::PreTranslateMessage(pMsg);
}

4.3 整体



5 相应功能对应的代码

5.1 lognx

case 6:
		{
			if (mNum1 < 0 || mNum2 < 0 || mNum1 == 1)
			{
				MessageBox(TEXT("该对数无效,请重新输入!"));
				mStr = "";
				return;
			}
			else
				mResult = log(mNum2) / log(mNum1);
			break;
		}

5.2 e^x

case 7:
		{
			double item = 1;
			mResult = 1;
			int i = 1;
			do
			{
				item = item * mNum2 / i;
				i++;
				mResult += item;
			} while (fabs(item) > 1e-6);
			break;
		}

5.3 x!

case 8:
		{
			mResult = 1.0;
			for (long long i = 1; i <= long long(mNum1); i++)
				mResult *= i;
			break;
		}

5.4 sin

case 9:
		{
			long long num = mNum2;
			num %= 360;
			mNum1 = num;
			mNum1 = mNum1 / 180 * 3.1415926;
			double item = mNum1;
			mResult = mNum1;
			long long i = 1;
			do
			{
				item = -item * mNum1 * mNum1 / ((2 * i) * (2 * i + 1));
				mResult += item;//sinx=x-x^3/3!+x^5/5!-x^7/7!+...
				i++;
			} while (fabs(item) >= 1e-5);//当精度达到10的五次方时跳出
			break;
		}

5.5 cos

case 10:
		{
			long long num = mNum2;
			num %= 360;
			mNum1 = num;
			mNum1 = mNum1 / 180 * 3.1415926;
			double item = 1;
			mResult = 1;
			long long i = 1;
			do
			{
				item = -item * mNum1 * mNum1 / ((2 * i) * (2 * i - 1));
				mResult += item;//cosx=1-x^2/2!+x^4/4!-x^6/6!+...
				i++;
			} while (fabs(item) >= 1e-5);//当精度达到10的五次方时跳出
			break;
		}

5.6 tan

case 11:
		{
			long long num = mNum2;
			num %= 180;
			if (num == 90 || num == -90)//去除不再范围内的数
			{
				MessageBox(TEXT("此值不在正切函数的有效区域内,请重新输入"));
			}
			else
			{
				mNum1 = num;//将大度数化小
				mNum1 = mNum1 / 180 * 3.1415926;//化为弧度制
				mResult = tan(mNum1);
			}
			break;
		}

5.7 sqrt

case 12:
		mResult = sqrt(mNum1);
		break;
	}

计算器当中基本的输入,输出,计算,转换,归零,删除等操作

Dlag.h 声明,调用

Dlag.cpp 定义,实现

导入图片

6 简易计算器的优化

6.1 左上角关于窗口内容的修改

Dlg.h的文件>>资源视图>>IDD_ABOUTBOX>>在关于窗口内进行修改相关的内容


修改成如下格式


6.2 MFC自定义窗口添加背景图片

第一步 在Dlg.cpp的初始化函数OnInitDialog()里面添加背景图片的相关代码

// TODO: 在此添加额外的初始化代码
	CString sPath = _T("E:\\C++\\C++课程学习\\大作业\\HuangPengcalculator\\HuangPengcalculator\\res\\picture.jfif");//图片所存放的位置
	CImage img;//创建一个空白的图片对象img
	img.Load(sPath);//将图片背景载入到img里,此时img就可以代表图片了
	HBITMAP hbmp=img.Detach();//HBIT是windows位图的句柄;Detach释放图片资源,img.Detach释放之后会放回一个HBITMAP类型的值
	CBitmap bmp;//CBit是C++中的位图对象
	bmp.Attach(hbmp);//将bmp和图片资源hbmp绑定

	m_bgBrush.CreatePatternBrush(&bmp);//CreatePatternBrush的作用是初始化使用位图指定模式的笔画,此时已经创建了设置背景时会使用到的笔刷


	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE


/*
	图片所存放的位置的注意事项
	1.要用“\\”,而不能用“\”
	2.picture.jfif要带有图片文件的类型“.jfif”,不能只写picture,否则无法正常编译
	E:\\C++\\C++课程学习\\大作业\\HuangPengcalculator\\HuangPengcalculator\\res\\picture.jfif
*/

第二步 在头文件Dlg.h的public域下加以下代码

public:
	CBrush m_bgBrush;//设置背景图片的成员变量m_bgBrush

第三步 项目>>类向导>>消息>>搜索两个函数WM_CTLCOLOR(控制窗口显示样式的消息响应函数)和WM_NCHITTEST>>并双击这两个函数进行添加>>于是在Dlg.cpp最底下会出现这两个函数对应的代码>>对这两个函数内部添加代码


第四步 对这两个函数内部添加代码

HBRUSH CHuangPengcalculatorDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)//OnCtlColor函数是控制我们窗口显示样式的响应函数;pWnd是窗口的指针
{
	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);

	// TODO:  在此更改 DC 的任何特性

	// TODO:  如果默认的不是所需画笔,则返回另一个画笔
	if (pWnd==this)//如果pWnd==this是我们的当前窗口的话,就把我们刚刚创建的背景底数给它返回
	{
		return m_bgBrush;
	}


	return hbr;
}


LRESULT CHuangPengcalculatorDlg::OnNcHitTest(CPoint point)//如果当设置类型去掉了默认的标题栏,就无法拖动窗口了,该函数用于解决此情况窗口不能拖动的情况
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	LRESULT ret = CDialogEx::OnNcHitTest(point);//CDialogEx::OnNcHitTest(point)是一个LRESULT类型的返回值
	return ret == HTCLIENT ? HTCAPTION: ret;//判断,这个ret是我们接收到的消息,HTCLIENT表示的是窗口,如果接收到的消息是窗口的话,此时因为设置去掉了默认的标题栏,就应该把这个消息改成标题栏,返回一个HTCAPTION,HTCAPTION表示模拟一个标题,这样窗口就改成标题栏了,就可以拖动了;如果不是窗口HTCLIENT,就把ret原路返回,因为此时的窗口自带默认的标题栏可以拖动
}

7 MFC的帮助文档

7.1 在Visual Studio界面查找MFC文档



7.2 在百度上搜索MFC的帮助文档网址

MFC的帮助文档网址:https://learn.microsoft.com/zh-cn/cpp/mfc/,查找帮助MFC文档

8 Visual Studio的调试方法

8.1 直接运行调试

直接运行调试,根据错误列表,进行修改

8.2 运用断点调试

posted @ 2023-02-06 14:57  bujidao1128  阅读(720)  评论(0编辑  收藏  举报