我的CSDN开篇第一博

新人任务一:基于Visual Studio C++的MFC简单计算器

前言

算是纪念自己头一次开始结合自己所学写简单的“小项目”,实际上还是很“菜”的。

开始时无论是对于编程语言本身的掌握(目前学习到的C++和Java),还是有一个大概的框架规划,我都感觉自己无从下手,因此也去“临时抱佛脚”再学了一些,CSDN 也好,B站也罢,总之确实学到的不少,因此记录下来,算是见证自己的进步吧!

前期准备

一、MFC的基本介绍

百度百科的解释:MFC全称为Microsoft Foundation Classes ,是微软公司提供的一个类库,以C++的形式封装了Windows API,并且包含一个应用程序框架,便于应用程序开发人员使用!

在VS中创建MFC项目

为了实现用C++编写实现可视化的简单计算器,我选择Visual Studio 2019版本中的MFC来开发这个小项目,此外还参考了B站的MFC基本操作的视频,用以更好的帮助自己完成项目!

二、算术表达式
1、算术表达式的特点:
(1)操作数之间的相对次序不变;
(2)运算符的相对次序不同;
(3)后缀表达式中已考虑了运算符的优先级,没有括号,只有操作数和运算符。

列:算术表达式求值 :参与运算的数据(即操作数)可以为整数或实数,运算符(即操作符)为+、-、、/(加、减、乘、除)等二元操作符,包括圆括号;
如 :
5
6+10-25=15或者 6+(5-4/2)*3=15
运算规则:先乘除,后加减,从左到右计算,先括号内,后括号外;

中缀与后缀表达式
2、中缀表达式转换为后缀表达式
(1)存储结构

①后缀表达式队列:postQueue,用于存储逆波兰表达式(其实不用队列排序直接输出也行)

②操作符栈:opStack,对用户输入的操作符进行处理,用于存储运算符

(2)算法思想

从左向右依次读取算术表达式的元素X,分以下情况进行不同的处理:
1)如果X是操作数,直接入队
2)如果X是运算符,再分以下情况:
 	 a)如果栈为空,直接入栈。
 	 b)如果X==”(“,直接入栈。
 	 c)如果X==”)“,则将栈里的元素逐个出栈,并入队到后缀表达式队列中,直到第一个配对的”(”出栈。(注:“(”和“)”都不 入队)
 	 d)如果是其他操作符(+ - * /),则和栈顶元素进行比较优先级。 如果栈顶元素的优先级大于等于X,则出栈并把栈中弹出的元素入队,直到栈顶元素的优先级小于X或者栈为空。弹出完这些元素后,才将遇到的操作符压入到栈中。
3)最后将栈中剩余的操作符全部入队。

3、后缀表达式的计算
(1)需要用到一个结果栈Res_Stack :用于存放计算的中间过程的值和最终结果

(2)算法思想
后缀表达式计算

首先准备一个栈Res_Stack.
1)从左开始向右遍历后缀表达式的元素。
2)如果取到的元素是操作数,直接入栈Res_Stack,如果是运算符,从栈中弹出2个数进行运算,然后把运算结果入栈
3) 当遍历完后缀表达式时,计算结果就保存在栈里了。

设计思路

1、首先是创建一个MFC项目用来显示基本的窗口
2、之后创建相应的“.h” 头文件
3、接着创建“.cpp”源文件用于实现计算器功能及可视化

具体实现

1、首先是如何通过MFC显示一个窗口
第一步第二部第三部2、“.h”文件的创建

// xch-CakulatorDlg.h: 头文件
//
#pragma once

//运算符

enum Calcuator_Flag
{
	FLAG_ADD,
	FLAG_SUB,
	FLAG_MUL,
	FLAG_DIV,
};


// CxchCakulatorDlg 对话框
class CxchCakulatorDlg : public CDialogEx
{

// 构造

public:
CxchCakulatorDlg(CWnd* pParent = nullptr);	// 标准构造函数
void SaveFirstValue();	//保存第一个输入值
void Calculator();		//计算

// 对话框数据

#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_XCHCAKULATOR_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()
private:
CString str;	//编辑框1内的字符
CString str1;	//编辑框2内的字符
CString str2;
CString str3;
CString str4;
CString str5;
CString str6;
CString TempStr;
double  NUM1;	//输入两个数
double  NUM2;
Calcuator_Flag Flag;

public:
afx_msg void OnBnClickedButtonnum0();
afx_msg void OnBnClickedButtonnum1();
afx_msg void OnBnClickedButtonnum2();
afx_msg void OnBnClickedButtonnum3();
afx_msg void OnBnClickedButtonnum4();
afx_msg void OnBnClickedButtonnum5();
afx_msg void OnBnClickedButtonnum6();
afx_msg void OnBnClickedButtonnum7();
afx_msg void OnBnClickedButtonnum8();
afx_msg void OnBnClickedButtonnum9();
afx_msg void OnBnClickedButtonback();
afx_msg void OnBnClickedButtonclear();
afx_msg void OnBnClickedButtonpoint();
afx_msg void OnBnClickedButtonadd();
afx_msg void OnBnClickedButtonsub();
afx_msg void OnBnClickedButtonmul();
afx_msg void OnBnClickedButtondiv();
afx_msg void OnBnClickedButtonequal();
afx_msg void OnBnClickedClearall();
};

3、“.c”文件的创建

// 
// 
// xch-CakulatorDlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "xch-Cakulator.h"
#include "xch-CakulatorDlg.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()


// CxchCakulatorDlg 对话框



CxchCakulatorDlg::CxchCakulatorDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_XCHCAKULATOR_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CxchCakulatorDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Text(pDX, IDC_EDIT1, str);
	DDX_Text(pDX, IDC_EDIT2, str1);
	DDX_Text(pDX, IDC_EDIT3, str2);
	DDX_Text(pDX, IDC_EDIT4, str3);
	DDX_Text(pDX, IDC_EDIT5, str4);
	DDX_Text(pDX, IDC_EDIT6, str5);
	DDX_Text(pDX, IDC_EDIT7, str6);

}

BEGIN_MESSAGE_MAP(CxchCakulatorDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTONNum0, &CxchCakulatorDlg::OnBnClickedButtonnum0)
	ON_BN_CLICKED(IDC_BUTTONNum1, &CxchCakulatorDlg::OnBnClickedButtonnum1)
	ON_BN_CLICKED(IDC_BUTTONNum2, &CxchCakulatorDlg::OnBnClickedButtonnum2)
	ON_BN_CLICKED(IDC_BUTTONNum3, &CxchCakulatorDlg::OnBnClickedButtonnum3)
	ON_BN_CLICKED(IDC_BUTTONNum4, &CxchCakulatorDlg::OnBnClickedButtonnum4)
	ON_BN_CLICKED(IDC_BUTTONNum5, &CxchCakulatorDlg::OnBnClickedButtonnum5)
	ON_BN_CLICKED(IDC_BUTTONNum6, &CxchCakulatorDlg::OnBnClickedButtonnum6)
	ON_BN_CLICKED(IDC_BUTTONNum7, &CxchCakulatorDlg::OnBnClickedButtonnum7)
	ON_BN_CLICKED(IDC_BUTTONNum8, &CxchCakulatorDlg::OnBnClickedButtonnum8)
	ON_BN_CLICKED(IDC_BUTTONNum9, &CxchCakulatorDlg::OnBnClickedButtonnum9)
	ON_BN_CLICKED(IDC_BUTTONBack, &CxchCakulatorDlg::OnBnClickedButtonback)
	ON_BN_CLICKED(IDC_BUTTONClear, &CxchCakulatorDlg::OnBnClickedButtonclear)
	ON_BN_CLICKED(IDC_BUTTONPoint, &CxchCakulatorDlg::OnBnClickedButtonpoint)
	ON_BN_CLICKED(IDC_BUTTONAdd, &CxchCakulatorDlg::OnBnClickedButtonadd)
	ON_BN_CLICKED(IDC_BUTTONSub, &CxchCakulatorDlg::OnBnClickedButtonsub)
	ON_BN_CLICKED(IDC_BUTTONMul, &CxchCakulatorDlg::OnBnClickedButtonmul)
	ON_BN_CLICKED(IDC_BUTTONDiv, &CxchCakulatorDlg::OnBnClickedButtondiv)
	ON_BN_CLICKED(IDC_BUTTONEqual, &CxchCakulatorDlg::OnBnClickedButtonequal)
	ON_BN_CLICKED(ClearAll, &CxchCakulatorDlg::OnBnClickedClearall)
END_MESSAGE_MAP()


// CxchCakulatorDlg 消息处理程序

BOOL CxchCakulatorDlg::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 CxchCakulatorDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

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

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




void CxchCakulatorDlg::SaveFirstValue()
{
	UpdateData(TRUE);
	NUM1 = _wtof(str);
	TempStr = str;
	str = L"";
	UpdateData(FALSE);
}

void CxchCakulatorDlg::Calculator()
{
	UpdateData(TRUE);
	NUM2 = _wtof(str);
	double result = 0.0f;
	switch (Flag)
	{
	case FLAG_ADD:
		result = NUM1 + NUM2;
		TempStr = TempStr + _T("+") + str + _T("=");
		break;
	case FLAG_SUB:
		result = NUM1 - NUM2;
		TempStr = TempStr + _T("-") + str + _T("=");
		break;
	case FLAG_MUL:
		result = NUM1 * NUM2;
		TempStr = TempStr + _T("*") + str + _T("=");
		break;
	case FLAG_DIV:
		if (NUM2 == 0.0f)
		{
			result = NUM1;
			TempStr = _T("--除数不能为0!!!--");
		}
		else
		{
			result = NUM1 / NUM2;
			TempStr = TempStr + _T("/") + str + _T("=");
			break;
		}
	default:
		break;
	}
	//如果浮点数是个整数,就显示为整数
	if (result - int(result) <= 1e-5)
	{
		str.Format(L"%d", (int)result);
	}
	else
	{
		str.Format(L"%f", result);
	}
	TempStr += str;
	str5 = str4;
	str4 = str3;
	str3 = str2;
	str2 = str1;
	str1 = TempStr;
	UpdateData(FALSE);

	NUM1 = result;
	NUM2 = 0.0f;
}




void CxchCakulatorDlg::OnBnClickedButtonnum0()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	str += L"0";
	UpdateData(FALSE);
}


void CxchCakulatorDlg::OnBnClickedButtonnum1()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	str += L"1";
	UpdateData(FALSE);
}


void CxchCakulatorDlg::OnBnClickedButtonnum2()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	str += L"2";
	UpdateData(FALSE);
}


void CxchCakulatorDlg::OnBnClickedButtonnum3()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	str += L"3";
	UpdateData(FALSE);
}


void CxchCakulatorDlg::OnBnClickedButtonnum4()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	str += L"4";
	UpdateData(FALSE);
}


void CxchCakulatorDlg::OnBnClickedButtonnum5()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	str += L"5";
	UpdateData(FALSE);
}


void CxchCakulatorDlg::OnBnClickedButtonnum6()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	str += L"6";
	UpdateData(FALSE);
}


void CxchCakulatorDlg::OnBnClickedButtonnum7()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	str += L"7";
	UpdateData(FALSE);
}


void CxchCakulatorDlg::OnBnClickedButtonnum8()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	str += L"8";
	UpdateData(FALSE);
}


void CxchCakulatorDlg::OnBnClickedButtonnum9()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	str += L"9";
	UpdateData(FALSE);
}





void CxchCakulatorDlg::OnBnClickedButtonback()	//Back
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	if (!str.IsEmpty())
	{
		str = str.Left(str.GetLength() - 1);
	}
	UpdateData(FALSE);
}


void CxchCakulatorDlg::OnBnClickedButtonclear()	//Clear
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	str = L"";
	NUM1 = 0.0f;
	NUM2 = 0.0f;
	Flag = FLAG_ADD;
	UpdateData(FALSE);
}


void CxchCakulatorDlg::OnBnClickedButtonpoint()	//小数点
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	//如果没有小数点,则添加小数点;如果有,则会略本次的小数点,保证最多1个
	if (-1 == str.Find(L'.'))
	{
		str += L".";
	}
	UpdateData(FALSE);
}


void CxchCakulatorDlg::OnBnClickedButtonadd()	//加
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	Flag = FLAG_ADD;
}


void CxchCakulatorDlg::OnBnClickedButtonsub()	//减
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	Flag = FLAG_SUB;
}


void CxchCakulatorDlg::OnBnClickedButtonmul()	//乘
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	Flag = FLAG_MUL;
}


void CxchCakulatorDlg::OnBnClickedButtondiv()	//除
{
	// TODO: 在此添加控件通知处理程序代码
	SaveFirstValue();
	Flag = FLAG_DIV;
}


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


void CxchCakulatorDlg::OnBnClickedClearall()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	str = L"";
	str1 = L"";
	str2 = L"";
	str3 = L"";
	str4 = L"";
	str5 = L"";
	NUM1 = 0.0f;
	NUM2 = 0.0f;
	Flag = FLAG_SUB;
	UpdateData(FALSE);
}

总结

1、结果展示:
在这里插入图片描述

新人一枚,主要还是看B站学的,但也稍微有了一些新的认识吧!希望后面会有更大的进步!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值