第六次左右(计算器第四步)

MyGitHub

可能由于文件太大超过了100m github上传不上去...

第六次左右(计算器第四步)_第1张图片

所以先附上网盘链接(提取码:84dn)
终于...据说是本学期的最后一次项目作业
由于本次作业接触的东西比较新,并且似乎近期内不怎么会再接触到,本次的博客会稍微冗长一些,加上自己的理解笔记,记录整个完成过程~以便日后回顾

本次作业主要内容是针对之前在五次作业中趋于完善的计算器做一个外包装——界面。

吓得我赶紧去搜了一下...
界面库选用了MFC(网络上据说QT更适合新手...但是我懒呀..现成的vs呢)

一开始手足无措...啊不,是手无足措。
于是找了个教程,照着做了个简单的加法运算器。才渐渐懂了大概思路。
***

  • 界面的初始化

    VS->File->New->Project->(Installed Templated->Visual C++)MFC->"NAME"->Dialog based->Finish
    于是在资源视图(Class View)中,可以看到Calculator.rc->Dialog(其他三个子项目前还没有美化到这个程度就不管啦~)下有两个对话框模版:IDD_ABOUTBOX 和 IDD_CALCULATOR_DIALOG ,每个对话框唯一的对应ID,前者不用管。后者需要我们编辑~

打开对话框界面,右上角的属性中,可以对这个对话框进行各方面的外观修改。边框啊,字体啊之类的(但是怎么改都很丑啊!!)属性旁是工具箱,里面是各种所需要的控件。

按照题目的要求,界面需要的 按钮button 有“数字键0~9,小数点.,加+-×÷,左右括号 ,等号=ESC键backspace键”。此外,还需要FILE按钮,还有两个编辑框Edit Control用来显示输入和输出的字符串~ 直接在工具箱中找到后拖动到对话框中编辑。

于是↓这是初始化的界面:
第六次左右(计算器第四步)_第2张图片

为了方便后期的操作,右键控件,杂项->ID,最好修改ID 为易区别的标识,例:IDC_num1。

  • 界面控件的编辑

    两个编辑框(Edit Control):
    为了方便(偷懒),于是将两个编辑框的变量都定义为CString类。要使编辑框有输出,就要给编辑框关联变量。右键->添加变量->(综合多个教程的良心推荐)变量名为(m_开头)m_cinstr/m_coutstr,类别修改为 value ,变量类型选择 CString。
    DODateExchange(CDataExchange* pDX)函数中就可以看到自动生成的变量代码。在此函数中,控件“编辑框”和所对应的变量进行数据交换~并且在此类中属于public,可被各函数调用。

第六次左右(计算器第四步)_第3张图片

这样子,可以直接在编辑框中对变量进行修改和显示:在光标的指引下输入。但是输出编辑框理论上是不应该支持直接修改结果的,并且题目有要求“通过键盘输入”,再并且光标输入不太美观。因此,为了更好地体现“通过键盘输入”和美化界面(→_→),将两个编辑框都设置成visable->true和disabled->true,只读,无光标。这样,输入和输出的字符串解决的差不多了。

其次是按钮(button):
按钮的定义应该是:按下这个按钮,相当于调用某个函数,执行某个命令。于是,我将除了某些功能键之外的按钮统一定义为m_cinstr 加上该按钮所对应的字符。例如按下1,即为m_cinstr字符串的末尾加上1
MFC中非常方便的是,在编辑界面按两下按钮,自动在xxxDlg.h中生成函数声明,xxxDlg.cpp中生成函数方法~

第六次左右(计算器第四步)_第4张图片

这边涉及到Cstring类的使用,在这里和string无异,可以通过简单的函数实现。

    UpdateData();
    m_cinstr += '1';
    UpdateData(FALSE);  //同步至显示区

######等号:
等号在这里是一个功能键,在向字符串传入=之后,调用函数对字符串m_cinstr进行一系列的处理。
由于m_cinstrCString类的字符串,与原函数所用的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键和backspace键

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'就是其对应的虚拟键代码。

  • FILE键

    这个界面似乎容不下多余的编辑框了,于是只好另起炉灶。将file文件输入输出都放在另一个对话框内。资源视图->Dialog->右键“插入对话框”,此对话框内:
    • 两个静态文本框作为提示。
    • 两个编辑框:显示路径
    • 两个按钮,用来打开文件夹
    • 俩系统自动生成的按钮“确定”和“取消”。

打开系统文件夹按钮:这个是直接看教程的,但是教程解释的不是很详细噢,大概就是利用固有的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()));  
      }  
    尽管我设置Clip children->true ,能显示控件,但是还是奇妙的效果~当我移动框的时候,这张图片仿佛在追着对话框 →_→ 还是丑点吧,实在。

  • 说实在真的很佩服学长,尤其是我看不懂自己的代码的时候(o´・ェ・`o),学长还能找出错误。 于是在上次修改的基础上,本次针对代码再次按照要求稍微修改了些。
    • 类名修改为动词,Print -> Printer, Scan -> Scanner ...
    • 方法名为动词+名词 如scan_m_cinstr(),readfile
    • 改造printner...这个还在学习...

最后,上图。
第六次左右(计算器第四步)_第5张图片

第六次左右(计算器第四步)_第6张图片

参考资料:

  • 鸡啄米MFC教程
  • 键盘响应Ⅰ
  • 键盘响应Ⅱ
  • MFC教程Ⅰ
  • MFC教程Ⅱ
  • MFC背景图片
  • CString
  • Cstring的转换

你可能感兴趣的:(第六次左右(计算器第四步))