计算机软件实习之计算器的实现

基于MFC的简单计算器的实现

对于实验项目的实现,采用MFC做计算器的图形界面,然后将求解表达式的方法封装成类,放到MFC中进行调用最终呈现出最后的效果展示。

求解算数表达式解题思路

对于算数表达式的求解,最快也是最准确的求解方式就是借助计算器。当然我们也很容易联想到,计算机的内部是怎么实现的,使用了什么数据结构,采用了什么比较新颖的算法。这些问题都是很容易联想到的。接下来我们就对拿到一个算数表达式该怎么解决进行分析。
1.首先,判断该算数表达式是不是合法的。比如出现运算符是连续出现的、表达式是以小数点开头、小数点和运算符一起相继出现等等这些都是不合法的。
2. 其次,对于求解表达式采用什么数据结构,很容易能想得到的就是借助于堆栈队列进行,也可以借助于二叉树进行
3. 还有就是如何处理运算符优先级的问题
4. 最后就是是否存在数据类型的转换,如整型转换为string或者double类型等等。

求值表达式代码的实现

1.表达式合法性的判断

  • 思路
    为了将在编写程序的过程中更加的简洁迅速,故将字符型单词符号转换成int型数据,其对应的转化关系如下表所示。
    单词符号对应数字
    +1
    -2
    *3
    /4
    数字5
    6
    )7
    我们用这样的表示方式进行转换,故此我们需要新的数据结构即的方式vector<pair<string, int>>此结构类似于int,只不过这个数据类型里面包含两个数据,即string和int两种数据类型。用这种数据类型将单词符号依次转换为对应的数字序号,存储到其中。在依次转换的过程中来判断表达式是否是合法的。参考博客.
  • 代码
#include <stack>
#include <cstring>
#include <vector>
#include <utility>
#include <iostream>
using namespace std;
int word_analysis(vector<pair<string, int>>& word, const string s)
{
	for (int i = 0; i < s.length(); i++)   //遍历
	{
		//如果是运算符则加入vector容器
		if (s[i] == '(' || s[i] == ')' || s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/')
		{
		//判断此时是括号时,再有两个不能出现的算数运算符
			if (s[i] == '(')
			{
				if (s[i + 1] == ')' || s[i + 1] == '+' || s[i + 1] == '-' || s[i + 1] == '*' || s[i + 1] == '/')
					return -1;
			}
			if (s[i] == ')')
			{
				if (s[i - 1] == '(' || s[i - 1] == '+' || s[i - 1] == '-' || s[i - 1] == '*' || s[i - 1] == '/')
					return -1;
			}
			//此时不是括号是左右两边不能是存在算数运算符
			if (s[i] != ')'&&s[i] != '(')
			{
				if (s[i - 1] == '+' || s[i - 1] == '-' || s[i - 1] == '*' || s[i - 1] == '/')
					return -1;
			}
			string temp;
			temp.push_back(s[i]);
			switch (s[i])
			{
				case '+':
					word.push_back(make_pair(temp, 1));
					break;
				case '-':
					word.push_back(make_pair(temp, 2));
					break;
				case '*':
					word.push_back(make_pair(temp, 3));
					break;
				case '/':
					word.push_back(make_pair(temp, 4));
					break;
				case '(':
					word.push_back(make_pair(temp, 6));
					break;
				case ')':
					word.push_back(make_pair(temp, 7));
					break;
			}
		}
		else if (s[i] >= '0'&&s[i] <= '9')
		{
			string temp;
			//如果是数字就是直接输入,但不是只有一个数字
			while (s[i] >= '0'&&s[i] <= '9')
			{
				temp.push_back(s[i]);
				++i;
			}
			//表达式前面的数字输入完成时
			if (s[i] == '.')
			{
				++i;  //如果是小数点就直接跳过
				if (s[i] >= '0'&&s[i] <= '9')
				{
					temp.push_back('.');
					while (s[i] >= '0'&&s[i] <= '9')
					{
						temp.push_back(s[i]);
						++i;
					}
				}
				//表示 . 后面不是数字表示表达式是错误的 
				else return -1;
			}
			word.push_back(make_pair(temp, 5));
			--i;
		}
		//表达式是以数字开头,表示表达式时错误的
		else return -1;
	}
	return 0;
}
int main()
{
	vector<pair<string, int>> word;  //pair<string,int>表示一个数据类型,这个类型有两个变量
	string s = "(1.5+5.789)*82-10/2";
	int err_num = word_analysis(word, s);
	if (err_num == -1)
	{
		cout << "表达式输出错误!" << endl;
	}
	else cout << "表达式没有错误" << endl;
	return 0;
}


运行结果展示:
在这里插入图片描述

2.表达存储过程及计算过程

  • 思路
    对于合法表达式,我们采用将中缀表达式转换成后缀表达式,此过程接触堆栈和队列进行,然后将后缀表达式通过堆栈进行求值。
  • 实现代码
    1)中缀转后缀
#include <iostream>
#include <string>
#include <stack>
using namespace std;
// 获取运算符的优先级
int is_prior(char c)
{
	switch (c)
	{
	case '+':
	case '-':
		return 1;
	case '*':
	case '/':
		return 2;
	default:
		return 0;
	}
}
// 判断是否是运算符
bool is_Operator(char c)
{
	switch (c)
	{
	case '+':
	case '-':
	case '*':
	case '/':
		return true;
	default:
		return false;
	}
}
// 中缀转后缀
string getPostfix(const string& s)
{
	string b;  // 输出
	stack<char> s1;  // 操作符栈
	for (int i = 0; i < s.size(); ++i)  //遍历字符串进行中缀转后缀
	{
		char c = s[i];
		if (is_Operator(c))
		{
			while (!s1.empty() && is_Operator(s1.top()) && is_prior(s1.top()) >= is_prior(c))
			{
				b.push_back(s1.top());
				s1.pop();
			}
			s1.push(c);
		}
		else if (c == '(')
		{
			s1.push(c);
		}
		else if (c == ')')
		{
			while (s1.top() != '(')
			{
				b.push_back(s1.top());
				s1.pop();
			}
			s1.pop();
		}
		else
		{
			b.push_back(c);
		}
	}
	while (!s1.empty())
	{
		b.push_back(s1.top());
		s1.pop();
	}
	return b;
}
int main()
{
	string s = "a+b*c+(d*e+f)*g";
	string postfix = getPostfix(s);
	cout << s << endl << postfix << endl;
	return 0;
}

测试结果展示:
在这里插入图片描述
2)后缀求值
后缀表达是转换完成之后就进行最终的求解运算

void popTwoNumbers(stack<int>& s, int& first, int& second)
{
	first = s.top();
	s.pop();
	second = s.top();
	s.pop();
}

// 计算后缀表达式的值
int expCalculate(const string& postfix)
{
	int first, second;
	stack<int> s;
	for (int i = 0; i < postfix.size(); ++i)
	{
		char c = postfix[i];
		switch (c)
		{
		case '+':
			popTwoNumbers(s, first, second);
			s.push(second + first);
			break;
		case '-':
			popTwoNumbers(s, first, second);
			s.push(second - first);
			break;
		case '*':
			popTwoNumbers(s, first, second);
			s.push(second*first);
			break;
		case '/':
			popTwoNumbers(s, first, second);
			s.push(second / first);
			break;
		default:
			s.push(c - '0');
			break;
		}
	}
	int result = s.top();
	s.pop();
	return result;
}

最终结合上述步骤进行测试:

int main()
{
	string expr = "5+2*(6-3)-4/2";
	string postfix = getPostfix(expr);
	int result = expCalculate(postfix);
	cout << "The result is: " << result << endl;
	return 0;
}

结果如图所示:
在这里插入图片描述

最后将上述所有代码封装成一个类,一个是.h文件一个.cpp文件添加到MFC工程中即可

MFC界面的设计

基础设置

使用工具箱中buttonEdit Control按钮进行设计一个最初的模板。如图所示:

在这里插入图片描述
代码如下:
再次之前需要把编辑器窗口添加一个mEdit变量,目的是可以更好的使用。

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

	// TODO:  在此添加控件通知处理程序代码
	static CFont Sfont;
	static CFont Bfont;
	//CFont font;//不加static 貌似改变不了字体大小
	Sfont.DeleteObject();
	Sfont.CreatePointFont(200, "隶书");
	//Bfont.CreatePointFont(150, "宋体");
	GetDlgItem(IDC_EDIT1)->SetFont(&Sfont);
	//GetDlgItem(IDC_BUTTON1)->SetFont(&Bfont);
}


void CMFCApplication1Dlg::OnBnClickedButton5()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T("5");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnBnClickedButton3()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T("3");
	mEdit.SetWindowText(cs);
}

CString opt;//表示运算符号
int num1;
int num2;
int result;
void CMFCApplication1Dlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T("1");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnBnClickedButton2()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T("2");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnBnClickedButton4()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T("4");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnBnClickedButton6()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T("6");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnBnClickedButton7()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T("7");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnBnClickedButton8()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T("8");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnBnClickedButton9()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T("9");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnBnClickedButton11()
{
	// TODO: 在此添加控件通知处理程序代码
	//CString cs;
	//mEdit.GetDlgItemText(IDC_EDIT1, cs);   //获取
	//num1 = _tstoi(cs);//字符串转换成整数
	//opt = "+";
	//SetDlgItemText(IDC_EDIT1,_T(" "));   //清空屏幕
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T("+");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnBnClickedButton12()
{
	// TODO: 在此添加控件通知处理程序代码
	// 更改背景颜色 
	CString str;
	mEdit.GetWindowText(str);
	CFile file;
    file.Open("D://2.txt", CFile::modeCreate | CFile::modeNoTruncate | CFile::modeWrite);

	// 写入文件  
	//memset(WriteBuf, 'a', sizeof(WriteBuf));
	file.SeekToEnd();
	file.Write(str, strlen(str));
	file.Write(_T("\r\n"), 2);
	// 关闭文件  
	file.Close();
	
	CT2CA pszConvertedAnsiString(str);
	string exp_str(pszConvertedAnsiString); // 从 LPCSTR 构造 string  
	if (exp_str != " ")
	{
		Expression e(exp_str);
		if (e.test())
		{
			string tmp;
			stringstream ss;
			ss << e.calculate();
			ss >> tmp;
			str = tmp.c_str();
		}
		else
		{
			str = "输入错误";
		}
		mEdit.SetWindowText(str);
		CFile file;
		file.Open("D://2.txt", CFile::modeCreate | CFile::modeNoTruncate | CFile::modeWrite);
		file.SeekToEnd();
		file.Write(str, strlen(str));
		file.Write(_T("\r\n"), 2);
		// 关闭文件  
		file.Close();
		
	}
}


void CMFCApplication1Dlg::OnBnClickedButton13()
{
	// TODO: 在此添加控件通知处理程序代码
	mEdit.SetWindowText(_T(""));
}


void CMFCApplication1Dlg::OnBnClickedButton14()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);  //获取信息
	cs.Delete(cs.GetLength() - 1);
	mEdit.SetWindowText(cs);  //显示信息
}

void CMFCApplication1Dlg::OnBnClickedButton19()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T("(");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnBnClickedButton20()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T(")");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnBnClickedButton10()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T("-");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnBnClickedButton17()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T("*");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnBnClickedButton18()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T("/");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnBnClickedButton16()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T(".");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnBnClickedButton15()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cs;
	mEdit.GetWindowText(cs);   //获取
	cs = cs + _T("0");
	mEdit.SetWindowText(cs);
}


void CMFCApplication1Dlg::OnEnChangeEdit2()
{
	// TODO:  如果该控件是 RICHEDIT 控件,它将不
	// 发送此通知,除非重写 CDialogEx::OnInitDialog()
	// 函数并调用 CRichEditCtrl().SetEventMask(),
	// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
	// TODO:  在此添加控件通知处理程序代码
	static CFont Sfont;
	static CFont Bfont;
	//CFont font;//不加static 貌似改变不了字体大小
	Sfont.DeleteObject();
	Sfont.CreatePointFont(200, "隶书");
	//Bfont.CreatePointFont(150, "宋体");
	GetDlgItem(IDC_EDIT1)->SetFont(&Sfont);
}


void CMFCApplication1Dlg::OnBnClickedButton21()
{
	// TODO: 在此添加控件通知处理程序代码
	//CString cs;
	//GetDlgItemText(IDC_EDIT1, cs);
	//SetDlgItemText(IDC_EDIT2, cs);
	CFile SourceFile;//数据文件
	CString SourceData;//定义一临时变量保存一条记录
	CString strtmp;
	CFileException ex;
	SourceFile.Open("D://2.txt", CFile::modeRead | CFile::shareDenyWrite, &ex);
	CArchive ar(&SourceFile, CArchive::load);
	while (NULL != ar.ReadString(SourceData))//循环读取文件,直到文件结束
	{
		strtmp += SourceData + "\r\n";
		if (SourceData == "")
			continue;//跳过文件头部的提示信息
	}
	SetDlgItemText(IDC_EDIT2, strtmp);
	printf("\r\n");
}



HBRUSH CMFCApplication1Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
	if (pWnd->GetDlgCtrlID() == (IDC_BUTTON3))    //主界面
	{
		//pDC->SetBkMode(TRANSPARENT);
		pDC->SetTextColor(RGB(30, 100, 20)); //设置文本颜色
		pDC->SetBkColor(RGB(200, 230, 215));  //字体背景色
		return HBRUSH(GetStockObject(HOLLOW_BRUSH));
	}
	// TODO:  在此更改 DC 的任何特性
	// TODO:  如果默认的不是所需画笔,则返回另一个画笔
	return hbr;
}


void CMFCApplication1Dlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值

	CDialogEx::OnDrawItem(nIDCtl, lpDrawItemStruct);
		CDC dc;
		dc.Attach(lpDrawItemStruct->hDC);//得到绘制的设备环境CDC
		ASSERT(lpDrawItemStruct->CtlType == ODT_BUTTON);
		CString strText;
		((CButton *)GetDlgItem(nIDCtl))->GetWindowText(strText);
		SetBkMode(lpDrawItemStruct->hDC, TRANSPARENT);//透明
		if (nIDCtl == IDC_BUTTON3)
		{
			if (GetDlgItem(IDC_BUTTON3)->IsWindowEnabled())  //当按钮不操作 & 按钮可用
			{
				CBrush brush(RGB(30, 200, 255));    //内背景画刷
				CPen m_BoundryPen(0, 2, RGB(80, 80, 80));   //边框画笔
				CBrush m_BackgroundBrush = RGB(140, 200, 255);    //大背景画刷
				dc.FillRect(&(lpDrawItemStruct->rcItem), &m_BackgroundBrush);//利用画刷brush,填充大矩形框	
				CRect rect = lpDrawItemStruct->rcItem;
				CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
				POINT pt;
				//画按钮的外边框,它是一个半径为10的圆角矩形
				pt.x = 10;
				pt.y = 10;
				CPen* hOldPen = pDC->SelectObject(&m_BoundryPen);
				pDC->RoundRect(&rect, pt);
				pDC->SelectObject(hOldPen);
				rect.DeflateRect(3, 3, 3, 3);   //缩进
				CBrush *pOldBrush = pDC->SelectObject(&m_BackgroundBrush);
				pDC->Rectangle(rect);    //画矩形
				pDC->SelectObject(pOldBrush);
				pDC->FillRect(rect, &brush);    //填充内矩形
				//因为这里进行了重绘,所以文字也要重绘
				DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(), &lpDrawItemStruct->rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
			}
			if (lpDrawItemStruct->itemState&ODS_SELECTED & GetDlgItem(IDC_BUTTON3)->IsWindowEnabled())    //如果按钮可用 & 点击
			{
				CBrush brush(RGB(0, 160, 230));    //内背景画刷
				CPen m_BoundryPen(0, 1, RGB(80, 80, 80));   //边框画笔
				CBrush m_BackgroundBrush = RGB(140, 200, 255);    //大背景画刷
				dc.FillRect(&(lpDrawItemStruct->rcItem), &m_BackgroundBrush);//利用画刷brush,填充矩形框	
				CRect rect = lpDrawItemStruct->rcItem;
				CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
				POINT pt;
				//画按钮的外边框,它是一个半径为5的圆角矩形
				pt.x = 10;
				pt.y = 10;
				CPen* hOldPen = pDC->SelectObject(&m_BoundryPen);
				pDC->RoundRect(&rect, pt);
				pDC->SelectObject(hOldPen);
				rect.DeflateRect(4, 4, 3, 3);
				CBrush *pOldBrush = pDC->SelectObject(&m_BackgroundBrush);
				pDC->Rectangle(rect);
				pDC->SelectObject(pOldBrush);
				pDC->FillRect(rect, &brush);
				//因为这里进行了重绘,所以文字也要重绘
				DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(), &lpDrawItemStruct->rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
			}
			if (!GetDlgItem(IDC_BUTTON3)->IsWindowEnabled())    //不可用,显示灰色
			{
				CBrush brush(RGB(190, 190, 200));    //内背景画刷
				CPen m_BoundryPen(0, 2, RGB(80, 80, 80));   //边框画笔
				CBrush m_BackgroundBrush = RGB(140, 200, 255);    //大背景画刷
				dc.FillRect(&(lpDrawItemStruct->rcItem), &m_BackgroundBrush);//利用画刷brush,填充矩形框	
				CRect rect = lpDrawItemStruct->rcItem;
				CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
				POINT pt;
				//画按钮的外边框,它是一个半径为5的圆角矩形
				pt.x = 10;
				pt.y = 10;
				CPen* hOldPen = pDC->SelectObject(&m_BoundryPen);
				pDC->RoundRect(&rect, pt);
				pDC->SelectObject(hOldPen);
				rect.DeflateRect(3, 3, 3, 3);
				CBrush *pOldBrush = pDC->SelectObject(&m_BackgroundBrush);
				pDC->Rectangle(rect);
				pDC->SelectObject(pOldBrush);
				pDC->FillRect(rect, &brush);
				//因为这里进行了重绘,所以文字也要重绘
				pDC->SetTextColor(RGB(235, 255, 255)); //设置文本颜色
				DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(), &lpDrawItemStruct->rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
			}
			dc.Detach();
		}
}

初始效果图如下:
在这里插入图片描述

功能的添加

1.历史记录的功能

  • 思路
    将计算数据编辑框中的数据一个写入txt文本之中保存下载,然后当点击历史记录功能时,在另外一个编辑框中调用此txt文档,然后进行显示
  • 实现代码
    历史记录控件设置代码:
void CMFCApplication1Dlg::OnBnClickedButton21()
{
	// TODO: 在此添加控件通知处理程序代码
	//CString cs;
	//GetDlgItemText(IDC_EDIT1, cs);
	//SetDlgItemText(IDC_EDIT2, cs);
	CFile SourceFile;//数据文件
	CString SourceData;//定义一临时变量保存一条记录
	CString strtmp;
	CFileException ex;
	SourceFile.Open("D://2.txt", CFile::modeRead | CFile::shareDenyWrite, &ex);
	CArchive ar(&SourceFile, CArchive::load);
	while (NULL != ar.ReadString(SourceData))//循环读取文件,直到文件结束
	{
		strtmp += SourceData + "\r\n";
		if (SourceData == "")
			continue;//跳过文件头部的提示信息
	}
	SetDlgItemText(IDC_EDIT2, strtmp);
	printf("\r\n");
}

在**=**控件设置代码如下:

void CMFCApplication1Dlg::OnBnClickedButton12()
{
	// TODO: 在此添加控件通知处理程序代码
	// 更改背景颜色 
	CString str;
	mEdit.GetWindowText(str);
	CFile file;
    file.Open("D://2.txt", CFile::modeCreate | CFile::modeNoTruncate | CFile::modeWrite);

	// 写入文件  
	//memset(WriteBuf, 'a', sizeof(WriteBuf));
	file.SeekToEnd();
	file.Write(str, strlen(str));
	file.Write(_T("\r\n"), 2);
	// 关闭文件  
	file.Close();
	
	CT2CA pszConvertedAnsiString(str);
	string exp_str(pszConvertedAnsiString); // 从 LPCSTR 构造 string  
	if (exp_str != " ")
	{
		Expression e(exp_str);
		if (e.test())
		{
			string tmp;
			stringstream ss;
			ss << e.calculate();
			ss >> tmp;
			str = tmp.c_str();
		}
		else
		{
			str = "输入错误";
		}
		mEdit.SetWindowText(str);
		CFile file;
		file.Open("D://2.txt", CFile::modeCreate | CFile::modeNoTruncate | CFile::modeWrite);
		file.SeekToEnd();
		file.Write(str, strlen(str));
		file.Write(_T("\r\n"), 2);
		// 关闭文件  
		file.Close();
	}
}

2.背景颜色的设置
首先将Owner Draw设置为False
在这里插入图片描述
然后在进行如下设置

void CMFCApplication1Dlg::OnPaint()
{
		CRect rect;
		CPaintDC dc(this);
		GetClientRect(rect);
		dc.FillSolidRect(rect, RGB(131,165,155));  //设置背景颜色
}

3.按钮颜色填充
添加加黑的两项
在这里插入图片描述
然后进行下列函数的赋值

HBRUSH CMFCApplication1Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
	if (pWnd->GetDlgCtrlID() == (IDC_BUTTON3))    //主界面
	{
		//pDC->SetBkMode(TRANSPARENT);
		pDC->SetTextColor(RGB(30, 100, 20)); //设置文本颜色
		pDC->SetBkColor(RGB(200, 230, 215));  //字体背景色
		return HBRUSH(GetStockObject(HOLLOW_BRUSH));
	}
	// TODO:  在此更改 DC 的任何特性
	// TODO:  如果默认的不是所需画笔,则返回另一个画笔
	return hbr;
}


void CMFCApplication1Dlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值

	CDialogEx::OnDrawItem(nIDCtl, lpDrawItemStruct);
		CDC dc;
		dc.Attach(lpDrawItemStruct->hDC);//得到绘制的设备环境CDC
		ASSERT(lpDrawItemStruct->CtlType == ODT_BUTTON);
		CString strText;
		((CButton *)GetDlgItem(nIDCtl))->GetWindowText(strText);
		SetBkMode(lpDrawItemStruct->hDC, TRANSPARENT);//透明
		if (nIDCtl == IDC_BUTTON3)
		{
			if (GetDlgItem(IDC_BUTTON3)->IsWindowEnabled())  //当按钮不操作 & 按钮可用
			{
				CBrush brush(RGB(30, 200, 255));    //内背景画刷
				CPen m_BoundryPen(0, 2, RGB(80, 80, 80));   //边框画笔
				CBrush m_BackgroundBrush = RGB(140, 200, 255);    //大背景画刷
				dc.FillRect(&(lpDrawItemStruct->rcItem), &m_BackgroundBrush);//利用画刷brush,填充大矩形框	
				CRect rect = lpDrawItemStruct->rcItem;
				CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
				POINT pt;
				//画按钮的外边框,它是一个半径为10的圆角矩形
				pt.x = 10;
				pt.y = 10;
				CPen* hOldPen = pDC->SelectObject(&m_BoundryPen);
				pDC->RoundRect(&rect, pt);
				pDC->SelectObject(hOldPen);
				rect.DeflateRect(3, 3, 3, 3);   //缩进
				CBrush *pOldBrush = pDC->SelectObject(&m_BackgroundBrush);
				pDC->Rectangle(rect);    //画矩形
				pDC->SelectObject(pOldBrush);
				pDC->FillRect(rect, &brush);    //填充内矩形
				//因为这里进行了重绘,所以文字也要重绘
				DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(), &lpDrawItemStruct->rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
			}
			if (lpDrawItemStruct->itemState&ODS_SELECTED & GetDlgItem(IDC_BUTTON3)->IsWindowEnabled())    //如果按钮可用 & 点击
			{
				CBrush brush(RGB(0, 160, 230));    //内背景画刷
				CPen m_BoundryPen(0, 1, RGB(80, 80, 80));   //边框画笔
				CBrush m_BackgroundBrush = RGB(140, 200, 255);    //大背景画刷
				dc.FillRect(&(lpDrawItemStruct->rcItem), &m_BackgroundBrush);//利用画刷brush,填充矩形框	
				CRect rect = lpDrawItemStruct->rcItem;
				CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
				POINT pt;
				//画按钮的外边框,它是一个半径为5的圆角矩形
				pt.x = 10;
				pt.y = 10;
				CPen* hOldPen = pDC->SelectObject(&m_BoundryPen);
				pDC->RoundRect(&rect, pt);
				pDC->SelectObject(hOldPen);
				rect.DeflateRect(4, 4, 3, 3);
				CBrush *pOldBrush = pDC->SelectObject(&m_BackgroundBrush);
				pDC->Rectangle(rect);
				pDC->SelectObject(pOldBrush);
				pDC->FillRect(rect, &brush);
				//因为这里进行了重绘,所以文字也要重绘
				DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(), &lpDrawItemStruct->rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
			}
			if (!GetDlgItem(IDC_BUTTON3)->IsWindowEnabled())    //不可用,显示灰色
			{
				CBrush brush(RGB(190, 190, 200));    //内背景画刷
				CPen m_BoundryPen(0, 2, RGB(80, 80, 80));   //边框画笔
				CBrush m_BackgroundBrush = RGB(140, 200, 255);    //大背景画刷
				dc.FillRect(&(lpDrawItemStruct->rcItem), &m_BackgroundBrush);//利用画刷brush,填充矩形框	
				CRect rect = lpDrawItemStruct->rcItem;
				CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
				POINT pt;
				//画按钮的外边框,它是一个半径为5的圆角矩形
				pt.x = 10;
				pt.y = 10;
				CPen* hOldPen = pDC->SelectObject(&m_BoundryPen);
				pDC->RoundRect(&rect, pt);
				pDC->SelectObject(hOldPen);
				rect.DeflateRect(3, 3, 3, 3);
				CBrush *pOldBrush = pDC->SelectObject(&m_BackgroundBrush);
				pDC->Rectangle(rect);
				pDC->SelectObject(pOldBrush);
				pDC->FillRect(rect, &brush);
				//因为这里进行了重绘,所以文字也要重绘
				pDC->SetTextColor(RGB(235, 255, 255)); //设置文本颜色
				DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(), &lpDrawItemStruct->rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
			}
			dc.Detach();
		}
} 

最终效果图展示如下:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值