可能由于文件太大超过了100m github上传不上去...
所以先附上网盘链接(提取码:84dn)
终于...据说是本学期的最后一次项目作业
由于本次作业接触的东西比较新,并且似乎近期内不怎么会再接触到,本次的博客会稍微冗长一些,加上自己的理解笔记,记录整个完成过程~以便日后回顾
本次作业主要内容是针对之前在五次作业中趋于完善的计算器做一个外包装——界面。
吓得我赶紧去搜了一下...
界面库选用了MFC(网络上据说QT更适合新手...但是我懒呀..现成的vs呢)
一开始手足无措...啊不,是手无足措。
于是找了个教程,照着做了个简单的加法运算器。才渐渐懂了大概思路。
***
打开对话框界面,右上角的属性中,可以对这个对话框进行各方面的外观修改。边框啊,字体啊之类的(但是怎么改都很丑啊!!)属性旁是工具箱,里面是各种所需要的控件。
按照题目的要求,界面需要的
按钮button
有“数字键0~9,小数点.
,加+
减-
乘×
除÷
,左右括号(
)
,等号=
,ESC键
,backspace
键”。此外,还需要FILE
按钮,还有两个编辑框Edit Control用来显示输入和输出的字符串~ 直接在工具箱中找到后拖动到对话框中编辑。
为了方便后期的操作,右键控件,杂项->ID,最好修改ID 为易区别的标识,例:IDC_num1。
DODateExchange(CDataExchange* pDX)
函数中就可以看到自动生成的变量代码。在此函数中,控件“编辑框”和所对应的变量进行数据交换~并且在此类中属于public,可被各函数调用。这样子,可以直接在编辑框中对变量进行修改和显示:在光标的指引下输入。但是输出编辑框理论上是不应该支持直接修改结果的,并且题目有要求“通过键盘输入”,再并且光标输入不太美观。因此,为了更好地体现“通过键盘输入”和美化界面(→_→),将两个编辑框都设置成visable->true和disabled->true,只读,无光标。这样,输入和输出的字符串解决的差不多了。
其次是按钮(button):
按钮的定义应该是:按下这个按钮,相当于调用某个函数,执行某个命令。于是,我将除了某些功能键之外的按钮统一定义为m_cinstr
加上该按钮所对应的字符。例如按下1
,即为m_cinstr
字符串的末尾加上1
。
MFC中非常方便的是,在编辑界面按两下按钮,自动在xxxDlg.h
中生成函数声明,xxxDlg.cpp
中生成函数方法~
这边涉及到Cstring
类的使用,在这里和string无异,可以通过简单的函数实现。
UpdateData();
m_cinstr += '1';
UpdateData(FALSE); //同步至显示区
######等号:
等号在这里是一个功能键,在向字符串传入=
之后,调用函数对字符串m_cinstr
进行一系列的处理。
由于m_cinstr
是CString
类的字符串,与原函数所用的string
不能等价。因此,需要先将Cstring转化为string类。网络上介绍了各种办法,如Getbuffer()....但是打开方式不对...都不行...谜之原因。找到了一个非常方便的办法
CString m_test;
string input;
double results;
//Cstring->string
USES_CONVERSION;
string input(W2A(m_cinstr));
//string->CString
m_test.Format(_T("%s"), input);
//double->Cstring
m_test.Format(_T("%f"), results);
转化后,对于字符串的操作基本和原函数一致。只需将结果转化为CString类传值给m_test就好~
1.一开始有苦恼过函数怎么实现→_→ 难道要都写在主函数里???然后发现可以直接派生~对应的对话框基类都是CDialogEX,派生出相应的Scanner和Printner类 ,之后就是愉快地复制粘贴。
但是这样很占空间,所以其实直接新建类就好了~
esc键对应的操作是“清空显示区”,所以直接
m_cinstr.Empty(); //清空
m_test.Empty();
UpdateData(FALSE);//同步至显示区
backspace键:就是退格键
m_cinstr = m_cinstr.Left(m_cinstr.GetLength() - 1); //提取左边的数值并将其长度减去1即好。
到此为止一个简单的计算器基本完成了,可以愉快地通过界面输入输出。
但是学长和老师都不会让我们这么轻松 QAQ,界面上有的按键还要通过键盘输入,换个专业点的词叫“键盘响应”。
采用重载'PreTranslateMessage'方法的方法,在xxxDlg.h内直接声明一个bool函数,cpp文件中:
BOOL CXXXDlg::PreTranslateMessage(MSG* pMsg)
{
//判断是否是键盘的消息
if(pMsg->message==WM_KEYDOWN)
{
//pMsg->wParam 为虚拟键代码
switch (pMsg->wParam)
{
//如果是数字键1
case VK_NUMPAD1:
OnBnClickednum1(); //则调用对应的函数
break;
}
}
return CDialog::PreTranslateMessage(pMsg);
}
左右括号的输入:组合键
由于括号无法直接从键盘上输入,于是有了组合键~在上述键盘响应的基础上,利用GetAsyncKeyState()获取键盘信息,稍作修改:
case '9':
if (GetAsyncKeyState(VK_SHIFT))
{
// 右shift+数字键9
OnBnClickedleftbracket();
}
break;
注意:小键盘之外的a->z,0->9直接通过写成'x'就是其对应的虚拟键代码。
打开系统文件夹按钮:这个是直接看教程的,但是教程解释的不是很详细噢,大概就是利用固有的CFileDialog类,声明一个对话框对象fileDlg,然后使用该类的函数实现目的。自己修改得接地气后,具体代码如下:
// 设置过滤器
TCHAR szFilter[] = _T("文本文件(*.txt)|*.txt|所有文件(*.*)|*.*||");
// 构造打开文件对话框
CFileDialog fileDlg(TRUE, _T("txt"), NULL, 0, szFilter, this);
CString strFilePath; //路径
// 显示打开文件对话框
if (IDOK == fileDlg.DoModal())
{
// 如果点击了文件对话框上的“你懒”按钮,通过GetPathName()获取文件路径
strFilePath = fileDlg.GetPathName();
m_filein_path = strFilePath; //将路径传至编辑框的变量m_filein_path
UpdateData(FALSE); //更新显示区
}
“确定”按钮:
和之前的等号一样,这是个功能按钮。按下“确定”后,调用Scanner类的对应函数,进行文件的读取,在Printner中写入。
关联主对话框:
calculator和file目前都是有自己功能的对话框,但是还需要将其关联起来,使file成为calculator 的子对话框。这个功能的设想为:按下主对话框的file键后,就能弹出file对话框。
因此,本质为类与类之间的互相调用。由于file对话框的主函数为Cfile类
,因此只需在file键的函数内添加
Cfile file; //创建Cfile类的对象
file.DoModal(); //DoModal()弹出函数
据说是界面的美化...
企图美化界面,但是不知道为什么迷之不能通过添加资源的bmp项目来更换背景。所以通过代码实现 '放在工程文件下的图片设置为背景' 。
修改onpaint()就行了
// CDialogEx::OnPaint();
CRect rc;
GetWindowRect(&rc);
CImage mImage;
if(mImage.Load(_T("1.jpg")) == S_OK)
{
//这里让图片绘制区域和窗口大小一致
mImage.Draw(GetDC()->GetSafeHdc(), CRect(0,0,rc.Width(),rc.Height()));
}
参考资料: