参考资料:

     1.MFC响应键盘
     2.计算器实例
     3.MFC文件对话框
     4.MFCUpdateData()函数的使用
     5.MFC教程
     6.winuser.h
     7.C++ 中int,char,string,CString类型转换

GitHub链接:传送门

题目链接:传送门

关于本次作业

一开始完全是无从下手,从选择"qt"还是"MFC"就开始犹豫,最后想到VS2015自带有MFC,省去重新安装"qt"的麻烦,选择了"MFC"(后来听说qt在实现上会简单很多,知道真相的喔眼泪掉下来)。因为这次作业所以重新开始使用VS,之前安装好就没怎么用,所以在软件的使用上又浪费了点时间去熟悉。查找了关于MFC的资料= =嗯,我想现在也没有时间去系统的学习它,所以放弃了整套的学习,直接查找关于MFC实现计算器方面的资料,又在GitHub上下载了几个计算器成品,把这些成品拆分掉才开始有了一点头绪。开始动手后,感觉跟高中时候会考要用的那个VB有点像,也是拖动各种工具然后去加代码= =但是还是天真了,毕竟不太一样的东西。最后算是勉勉强强实现了计算器图形界面。

实践中遇到的问题:

  • 1、关于键盘响应,一开始查找资料,顺利完成小键盘上数字的响应,但是主键盘上的数字却一直找不到其所对应的VK值,困扰了很久,最后才从一份文档中发现,MFC并没有关于主键盘上的字母所对应的VK值,而是采用直接引用的办法= =知道真相后有种欲哭无泪的感觉,很简单的解决办法,但是这过程花费了大把的时间。
  • 2、从编辑框中读取文件路径,一开始采用的方法是在编辑框中添加响应,通过UpdateData来更新,在输入文件路径的编辑框还算顺利,同样的办法用到输出文件路径的编辑框,程序运行后整个都卡住了。特别是如果我先在输出文件路径的编辑框中输入然后再在输入文件路径的编辑框输入路径,程序就不会卡,极度郁闷= =也找不到解决方法,其实现在对于这个问题还是懵懵的,最后加了一个button,按下之后才获取两个编辑框中的值进行批处理。
  • 3、在输入输出文件路径的编辑框中,不支持删除功能,最后用了两个button来清空,没有采用逐字删除的功能。
  • 4、键盘响应的问题,如果在输入输出文件的编辑框中使用了数字进行输入,计算器的显示区也会显示出这些数字,目前想到的解决办法是通过判断光标的位置,如果停在输入输出文件编辑框,则不键盘响应,但是这个方法没有成功,不知道是不是我判断焦点那块代码写得有问题,暂时没有很好的解决。

第三次更新:

为什么没有写第二次更新呢= =我忘了第二次更新的时候修复了什么bug。

  • 1、本次修改了光标停在文件编辑框输入以字母形式的文件名也会出现在计算显示区的问题。
  • 2、增加了支持文件输入输出编辑框的逐字删除。
  • 3、关于光标停在编辑框,键盘按键无法响应的问题,初次解决方案通过“关于本程序”的按钮弹出操作说明来告知使用者如何解决,后来考虑到并非人人都会点击“关于本程序”按钮,额外加了一个“消除”焦点的按钮。
  • 4、更改了显示区字体大小以及字体为“微软雅黑”(使用者电脑如果没有这个字体的话= =)

第四次更新

  • 1、修复了显示精度,诸如“(85.18-(-6140))(-93.28+1)=”能得出-233023.6104而不再是-233024以及对于表达式“-72-((-50-53)(-45*-91))=”得出-10851822而不是-1.08518e+007的问题
  • 2、改正了显示区当表达式过长停留在最先输入的字符上,支持从左到右的阅读顺序来显示表达式。
  • 3、主界面增加了最大化、最小化。
  • 4、更正了计算结果为0时显示为“-0”的错误(不小心发现学长的数据也有“-0”)
  • 5、修改了生成程序的默认图标,以及属性中版本等默认信息为个人信息。

未实现功能:

  • 1、使用者输入不合法表达式没有以弹窗模式进行警告,仅只是通过判断使程序不响应此操作。
  • 2、界面被吐槽丑= =确实硬伤,时间关系= =都是泪。
  • 3、没有增加按钮来支持显示科学表达式与普通表达式的转换

写在后面:

程序界面:


由于时间问题,对于界面的样式、字体等也没细弄,批处理区设在了主界面,没有弄成模态对话框的形式(我觉得不会很丑啊= =别打我= =),倒是增加了一个“关于本程序”的按钮,利用模态对话框来弹出另一个界面介绍程序。以后如果还有弄界面= = 我想我会果断选择qt了= =另外程序界面支持被随意拉伸,其实加个函数就能固定程序界面大小,但是我觉得这样随意拉伸挺好的,也就没有更改。还在不断改进,想到bug再来修改吧。

核心代码:

// 如果上一次按的是“=”按钮,清屏
void CCalculatorDlg::Clear()
{
    if (lastPress == true)
    {
        mEdit.SetWindowText(_T(""));
        lastPress = false;
    }
}

void CCalculatorDlg::OnBnClicked1()
{
    // 数字“1”按钮
    Clear();
    UpdateData(TRUE);
    CString str;
    mEdit.GetWindowText(str);
    str = str + _T("1");
    mEdit.SetWindowText(str);
    UpdateData(FALSE);
}

void CCalculatorDlg::OnBnClicked2()
{
    // 数字“2”按钮
    Clear();
    CString str;
    mEdit.GetWindowText(str);
    str = str + _T("2");
    mEdit.SetWindowText(str);
}

void CCalculatorDlg::OnBnClicked3()
{
    // 数字“3”按钮
    Clear();
    CString str;
    mEdit.GetWindowText(str);
    str = str + _T("3");
    mEdit.SetWindowText(str);
}

void CCalculatorDlg::OnBnClicked4()
{
    // 数字“4”按钮
    Clear();
    CString str;
    mEdit.GetWindowText(str);
    str = str + _T("4");
    mEdit.SetWindowText(str);
}

void CCalculatorDlg::OnBnClicked5()
{
    // 数字“5”按钮
    Clear();
    CString str;
    mEdit.GetWindowText(str);
    str = str + _T("5");
    mEdit.SetWindowText(str);
}

void CCalculatorDlg::OnBnClicked6()
{
    // 数字“6”按钮
    Clear();
    CString str;
    mEdit.GetWindowText(str);
    str = str + _T("6");
    mEdit.SetWindowText(str);
}

void CCalculatorDlg::OnBnClicked7()
{
    // 数字“7”按钮
    Clear();
    CString str;
    mEdit.GetWindowText(str);
    str = str + _T("7");
    mEdit.SetWindowText(str);
}

void CCalculatorDlg::OnBnClicked8()
{
    // 数字“8”按钮
    Clear();
    CString str;
    mEdit.GetWindowText(str);
    str = str + _T("8");
    mEdit.SetWindowText(str);
}

void CCalculatorDlg::OnBnClicked9()
{
    // 数字“9”按钮
    Clear();
    CString str;
    mEdit.GetWindowText(str);
    str = str + _T("9");
    mEdit.SetWindowText(str);
}

void CCalculatorDlg::OnBnClicked0()
{
    // 数字“0”按钮
    Clear();
    CString str;
    mEdit.GetWindowText(str);
    if (str != "0")
    {
        str = str + _T("0");
        mEdit.SetWindowText(str);
    }
}

void CCalculatorDlg::OnBnClickedClear()
{
    // “清屏”按钮
    mEdit.SetWindowText(_T(""));
}

void CCalculatorDlg::OnBnClickedBack()
{
    // “后退”按钮
    Clear();
    CString str;
    mEdit.GetWindowText(str);
    str = str.Left(str.GetLength()-1);
    mEdit.SetWindowText(str);
}

void CCalculatorDlg::OnBnClickedLeft()
{
    // “左括号”按钮
    Clear();
    CString str;
    mEdit.GetWindowText(str);
    if (str == "")
    {
        str = str + _T("(");
        mEdit.SetWindowText(str);
    }
    else
    {
        if(str.GetAt(str.GetLength()-1)<'0' || str.GetAt(str.GetLength()-1)>'9')
        {
            str = str + _T("(");
            mEdit.SetWindowText(str);
        }
    }
}

void CCalculatorDlg::OnBnClickedRight()
{
    // “右括号”按钮
    Clear();
    CString str;
    mEdit.GetWindowText(str);
    if(str != "")
    {
        str = str + _T(")");
        mEdit.SetWindowText(str);
    }
}

void CCalculatorDlg::OnBnClickedDot()
{
    // "."按钮
    Clear();
    CString str;
    mEdit.GetWindowText(str);
    if(str != "")
    {
        if(str.GetAt(str.GetLength()-1)>='0' && str.GetAt(str.GetLength()-1)<='9')
        {
            str = str + _T(".");
            mEdit.SetWindowText(str);
        }
    }
}

void CCalculatorDlg::OnBnClickedAdd()
{
    // 加号
    lastPress = false;
    CString str;
    mEdit.GetWindowText(str);
    str = str + _T("+");
    mEdit.SetWindowText(str);
}

void CCalculatorDlg::OnBnClickedSub()
{
    // 减号
    lastPress = false;
    CString str;
    mEdit.GetWindowText(str);
    str = str + _T("-");
    mEdit.SetWindowText(str);
}

void CCalculatorDlg::OnBnClickedMul()
{
    // 乘号
    lastPress = false;
    CString str;
    mEdit.GetWindowText(str);
    if(str != "")
    {
        if(str.GetAt(str.GetLength()-1)!='+' && str.GetAt(str.GetLength()-1)!='-'
            && str.GetAt(str.GetLength()-1)!='*' && str.GetAt(str.GetLength()-1)!='/')
        {
            str = str + _T("*");
            mEdit.SetWindowText(str);
        }
    }
}

void CCalculatorDlg::OnBnClickedDiv()
{
    // 除号
    lastPress = false;
    CString str;
    mEdit.GetWindowText(str);
    if(str != "")
    {
        if(str.GetAt(str.GetLength()-1)!='+' && str.GetAt(str.GetLength()-1)!='-'
            && str.GetAt(str.GetLength()-1)!='*' && str.GetAt(str.GetLength()-1)!='/')
        {
            str = str + _T("/");
            mEdit.SetWindowText(str);
        }
    }
}

void CCalculatorDlg::OnBnClickedEql()
{
    // 等号,计算结果
    CString str;
    mEdit.GetWindowText(str);
    if(str.Find('+')==-1 && str.Find('-')==-1 && str.Find('*')==-1 && str.Find('/')==-1)
        return;
    else
        lastPress = true;

    CT2CA pszConvertedAnsiString(str);  // 将 TCHAR 转换为 LPCSTR
    string exp_str(pszConvertedAnsiString); // 从 LPCSTR 构造 string

    que = ipt.ToStringQueue(exp_str);
    if (que.empty())
    {
        str = "ERROR";
    }
    else
    {
        string tmp;
        stringstream ss;
        ss.precision(10);
        stk = cal.NumCalculator(que);
        ss << stk.top();
        ss >> tmp;
        str = tmp.c_str();
    }
    mEdit.SetWindowText(str);
}

BOOL CCalculatorDlg::PreTranslateMessage(MSG* pMsg)
{
    bool flag = true;
    CWnd *pFocusWnd = GetFocus();
    if (pFocusWnd && (pFocusWnd == GetDlgItem(IDC_OPEN_EDIT) || pFocusWnd == GetDlgItem(IDC_SAVE_EDIT)))
    {
        flag = false;
    }
    else
    {
        flag = true;
    }
    if (pMsg->message == WM_KEYDOWN && flag)
        {
            switch (pMsg->wParam)
            {
            case VK_NUMPAD0:
                OnBnClicked0(); break;
            case VK_NUMPAD1:
            case '1':
                OnBnClicked1(); break;
            case '2':
            case VK_NUMPAD2:
                OnBnClicked2(); break;
            case '3':
            case VK_NUMPAD3:
                OnBnClicked3(); break;
            case '4':
            case VK_NUMPAD4:
                OnBnClicked4(); break;
            case '5':
            case VK_NUMPAD5:
                OnBnClicked5(); break;
            case '6':
            case VK_NUMPAD6:
                OnBnClicked6(); break;
            case '7':
            case VK_NUMPAD7:
                OnBnClicked7(); break;
            case VK_NUMPAD8:
                OnBnClicked8(); break;
            case VK_NUMPAD9:
                OnBnClicked9();
                break;
            case '8':
                if (GetKeyState(VK_SHIFT) < 0)
                {
                    OnBnClickedMul();
                }
                else
                {
                    OnBnClicked8();
                }
                break;
            case '9':
                if (GetKeyState(VK_SHIFT) < 0)
                {
                    OnBnClickedLeft();
                }
                else
                {
                    OnBnClicked9();
                }
                break;
            case '0':
                if (GetKeyState(VK_SHIFT) < 0)
                {
                    OnBnClickedRight();
                }
                else
                {
                    OnBnClicked0();
                }
                break;
            case VK_OEM_PLUS:
                if (GetKeyState(VK_SHIFT) < 0)
                {
                    OnBnClickedAdd();
                }
                else
                {
                    OnBnClickedEql();
                }
                break;
            case VK_OEM_PERIOD:
            case VK_DECIMAL:
                OnBnClickedDot(); break;
            case VK_SUBTRACT:
            case VK_OEM_MINUS:
                OnBnClickedSub(); break;
            case VK_DIVIDE:
            case VK_OEM_2:
                OnBnClickedDiv(); break;
            case VK_ADD:
                OnBnClickedAdd(); break;
            case VK_MULTIPLY:
                OnBnClickedMul(); break;
            case VK_BACK:
                OnBnClickedBack(); break;
            case VK_RETURN:
                OnBnClickedEql(); return TRUE;
            case VK_ESCAPE:
                OnBnClickedClear(); return TRUE;
            default:
                break;
            }
        }

    return CDialogEx::PreTranslateMessage(pMsg);
}

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

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

void CCalculatorDlg::OnBnClickedOpenButton()
{
    // TODO: 在此添加控件通知处理程序代码
    // 设置过滤器
    TCHAR szFilter[] = _T("文本文件(*.txt)|*.txt|所有文件(*.*)|*.*||");
    // 构造打开文件对话框
    CFileDialog fileDlg(TRUE, _T("txt"), NULL, 0, szFilter, this);
    CString strFilePath;

    // 显示打开文件对话框
    if (IDOK == fileDlg.DoModal())
    {
        // 如果点击了文件对话框上的“打开”按钮,则将选择的文件路径显示到编辑框里
        strFilePath = fileDlg.GetPathName();
        //tEdit.SetWindowText(strFilePath);
        SetDlgItemText(IDC_OPEN_EDIT, strFilePath);

        //SetDlgItemText(IDC_OPEN_EDIT, L" ");
    }
}

void CCalculatorDlg::OnBnClickedSaveButton()
{
    // TODO: 在此添加控件通知处理程序代码
    // 设置过滤器
    TCHAR szFilter[] = _T("文本文件(*.txt)|*.txt|Word文件(*.doc)|*.doc|所有文件(*.*)|*.*||");
    // 构造保存文件对话框
    CFileDialog fileDlg(FALSE, _T("doc"), _T("my"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter, this);
    CString strFilePath;

    // 显示保存文件对话框
    if (IDOK == fileDlg.DoModal())
    {
        // 如果点击了文件对话框上的“保存”按钮,则将选择的文件路径显示到编辑框里
        strFilePath = fileDlg.GetPathName();
        SetDlgItemText(IDC_SAVE_EDIT, strFilePath);
    }
}

void CCalculatorDlg::OnEnChangeOpenEdit()
{
    // TODO:  在此添加控件通知处理程序代码
    CString strFilePath;
    CString strFile;
    UpdateData(TRUE);
    tEdit.GetWindowText(strFile);
    strFilePath = strFilePath + strFile;
    UpdateData(FALSE);
    CT2CA pszConvertedAnsiString(strFilePath);  // 将 TCHAR 转换为 LPCSTR
    string test_str(pszConvertedAnsiString); // 从 LPCSTR 构造 string
    test_str_ = test_str;
}

void CCalculatorDlg::OnEnChangeSaveEdit()
{
    // TODO:  在此添加控件通知处理程序代码
    CString strFilePath;
    CString strFile;
    UpdateData(TRUE);
    rEdit.GetWindowText(strFile);
    strFilePath = strFilePath + strFile;
    UpdateData(FALSE);
    CT2CA pszConvertedAnsiString(strFilePath);  // 将 TCHAR 转换为 LPCSTR
    string results_str(pszConvertedAnsiString); // 从 LPCSTR 构造 string
    results_str_ = results_str;
}

void CCalculatorDlg::OnBnClickedOk()
{
    // TODO: 在此添加控件通知处理程序代码
    ipt.FileOpen(test_str_);
    opt.FileOpen(results_str_);
    if (!ipt.FileIsOpen())
    {
        cerr << "Could not open " << results_str_ << endl;
        ipt.FileClear();
    }
    else
    {
        while (!ipt.IsEof())
        {
            ipt.Read();
            //getline(ipt.fin, ipt.in);
            if (ipt.in == "")
            {
                continue;
            }
            que = ipt.ToStringQueue(ipt.in);
            if (que.empty())
            {
                opt.OutputToFile(que);
            }
            else
            {
                stk = cal.NumCalculator(que);
                opt.PutAnsTofile(stk);
            }
        }
    }
    ipt.FileClose();
    opt.FileClose();
}

void CCalculatorDlg::OnBnClickedClear1()
{
    //清空文件输入路径内容
    tEdit.SetWindowText(_T(""));
}

void CCalculatorDlg::OnBnClickedClear2()
{
    //清空文件输出路径内容
    rEdit.SetWindowText(_T(""));
}

void CCalculatorDlg::OnBnClickedButtonAbout()
{
    // TODO: 在此添加控件通知处理程序代码
    INT_PTR nRes;             // 用于保存DoModal函数的返回值   

    CTipDlg tipDlg;           // 构造对话框类CTipDlg的实例
    nRes = tipDlg.DoModal();  // 弹出对话框
    if (IDCANCEL == nRes)     // 判断对话框退出后返回值是否为IDCANCEL,如果是则return,否则继续向下执行
        return;
}

void CCalculatorDlg::OnBnClickedButtonOk()
{
    // TODO: 在此添加控件通知处理程序代码
    CWnd *pFocusWnd = GetFocus();
    if (pFocusWnd && (pFocusWnd == GetDlgItem(IDC_OPEN_EDIT)))
    {
        tEdit.SetWindowText(_T(""));
    }
    else if (pFocusWnd && (pFocusWnd == GetDlgItem(IDC_SAVE_EDIT)))
    {
        rEdit.SetWindowText(_T(""));
    }
}

第六次作业——利用MFC实现计算器图形界面以及简单四则运算表达式批处理的更多相关文章

  1. 利用MFC编写计算器

    端午节这两天没什么事,就用MFC写了一个简单的计算器,界面做的也比较简单,如下图1,可以进行简单的加.减.乘和除功能,小数点显示这块做的不是很好,比如输入1.2,不会一个个的显示,而是先显示“1”,后 ...

  2. 初进MFC的世界,太奇妙。第六次作业----未完待续

    又一次的迁徙.我希望能够早些抵达. 第六次作业-未完待续!图形界面,计算器文件 本次的作业是给自己的计算器加一个可视化的窗口,我开始也是很激动和憧憬的,看了很多的界面库,发现并没有想象的那么简单,因为 ...

  3. C++第六次作业

    前言 拿到作业的时候,整个人都不好了,虽然之前和同学说以后一起写游戏,画界面,然而现在的自己对界面的知识一窍不通,虽然同学分享了一些资料,但是通过这次作业,发现自己火候还是不够-- 问题描述及仓库地址 ...

  4. 《ABCD组》第六次作业:团队项目系统设计改进与详细设计

    <ABCD组>第六次作业:团队项目系统设计改进与详细设计 项目 内容 这个作业属于哪个课程 http://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 ht ...

  5. 耿丹CS16-2班第六次作业汇总

    Deadline: 2016-11-13 11:59 作业内容 第六次作业总结 00.本次题目分值最高为**6分/题 × 7题 + 5分/篇 × 1篇 = 47分**,其中有新解法者每题加原创分**2 ...

  6. C2第六次作业解题报告

    看过题解后如果觉得还算有用,请帮忙加点我所在团队博客访问量 http://www.cnblogs.com/newbe/ http://www.cnblogs.com/newbe/p/4069834.h ...

  7. VS2010/MFC编程入门之二(利用MFC向导生成单文档应用程序框架)

    VS2010/MFC编程入门之二(利用MFC向导生成单文档应用程序框架)-软件开发-鸡啄米 http://www.jizhuomi.com/software/141.html   上一讲中讲了VS20 ...

  8. C语言程序设计第六次作业——循环结构(2)

    C语言程序设计第六次作业--循环结构(2) 之前的博客园图片没处理好,对大家说一声抱歉.希望大家能够多多指出我的错误,我来认真修改 ^ - ^ !. (1)改错题 序列求和:输入一个正实数eps,计算 ...

  9. Python开发——利用正则表达式实现计算器算法

    Python开发--利用正则表达式实现计算器算法 (1)不使用eval()等系统自带的计算方法 (2)实现四则混合运算.括号优先级解析 思路: 1.字符串预处理,将所有空格去除 2.判断是否存在括号运 ...

随机推荐

  1. 写个屏蔽百度搜索广告的Chrome插件

    工作生活都用百度比较多,毕竟它是目前为止感觉最好的国内PC搜索引擎.我纵使已经差不多炼成了一眼过滤广告的眼力,但始终觉得碍眼,感觉还是写个插件把它屏蔽了吧.这个插件开发的门槛其实非常低,只是一开始做不 ...

  2. 支付宝Cookie高危漏洞引发的思考

    背景:当时我在做公司的网站支付接入,在调试支付宝WAP支付时,发现一些匪夷所思的事情: 1.我想要切换账号时退到需要输入登录信息时,原账号并没有退出,我按一下后退键又回来了: 2.我关闭浏览器也没有退 ...

  3. 项目分享五:H5图片压缩与上传

    一.简介 图片的压缩与上传,是APP里一个很常用的功能.我们来年看 ChiTuStore 是怎样做的.相关文件 App/Module/User/UserInfo.html,App/Module/Use ...

  4. 一个用react+nodejs实现的笔记本小应用

    寒假回家产品经理一直叮嘱着要继续做学校团队的辣个项目,但是...,我到现在一点都还没做,而且还销声匿迹躲了起来藏了几天,是的我干了票大的,想把项目用一种新的架构实现了,所以这几天一直在偷偷摸摸的做一些 ...

  5. PHP中JSON的跨域调用

    主调文件index.html <script type="text/javascript"> function getProfile(str) { var arr = ...

  6. Python 3 与 MySQL 5.6

    主要简单说下Python 3.3搭配MySQL Community Server 5.6的使用.在Python 3系列和MySQL 5.0系列里面下面的代码应该都通用.(没有验证) 准备 python ...

  7. 一个奇妙的java坑:Long 类型的比较

    Long userId=127L; Long authorId=127L; System.out.println(userId==authorId);//true userId=128L; autho ...

  8. 51-du 显示关于目录层次结构或文件磁盘使用情况的信息

    显示关于目录层次结构或文件磁盘使用情况的信息 du [options] [path-list] 参数 不带任何参数的du将显示工作目录及其子目录磁盘使用情况的信息,path-list指定要获取磁盘占用 ...

  9. linux系统数据落盘之细节

      本文节选自这里,原文以mysql innodb系统为例,介绍了数据经过的各层级的buffer和cache,其它系统也有相似的原理,摘录于此. 3.  VFS层 该层的缓冲都放在主机内存中,它的目的 ...

  10. Struts2进行url重写

    一般来说我们在用Struts2进行开发的时候我们的访问url都是带上一些类似于.action或者.do还有用?传递参数,这种访问方式与静态页面的访问相比,我就可以用一些开源的组件来进行url的重写,以 ...