c++计算器后续(5)

自娱自乐:

大概是重新开始玩qt,然后MFC和第四步附加的作业大概不会去玩了。以上。

QT相关:

阶段一:

原来作业里举了qt和mfc这两个做界面的东西,网上都说qt容易上手,学了mfc再来看qt简直真爱之类的,而且当初也没有装vs(dev c++确实也够用。。。),所以就当时就选了qt咯。教程什么的感觉不好找(向来就不大会找资料也是很渣。。。不过抛弃百度,用必应和谷歌之后倒是感觉好点),感觉不错的教程又好长,大概看不完。。。种种理由(明明大家都是一样的时间,差距大概就是在这吧),所以当初只是找了个qt计算器的模板,照着大概看得懂的打了一些,然而还是没做完。现在是想认真的看看教程,知其然还要知其所以然,实际上顶多是知道个大概的程度就满意了。最后这是感觉不错的两个教程:教程一教程二(如果看得下去的话,内容确实很多很详细,大概还在更)。

决定从头开始玩qt,于是把qt和vs都卸了重装,发现qt原来好像装错版本了,然后vs还是试用期已过。。。原来装的qt用的是MSVC编译器,所以才又得装vs,其实直接装MinGW编译的就好,然后vs登陆了半天大概是能用了(虽然我还不会用。。。)。接下来就开始看教程,虽然很多感觉计算器界面用不到,但是也能长长见识,毕竟是白得不能再白的小白。然而终究还是看不下去,看不多久就开始困,几天下来也没看多少,所以大概是带着看进去的一点东西先来完成一部分的界面。

这个阶段的界面只支持按钮输入,还没有关联键盘的输入,批量运算也还没实现,只能做到一些简单的计算器该有的东西,大概就是按按钮输入,按等号计算输出,下次计算自动清空。目前界面大概长这样:

然后来写写一些我想写的东西。一是刚开始在qt creator创建新项目的时候,它会有五个文件,然后里面的初始代码就看不懂,这个在教程里面也都有讲到,不然还有这个链接。我想说的是界面文件里面的那个有命名空间ui的类和那个文件里面的不是同一个东西,只是名字一样而已,然后想改类名的话还是在添加界面文件时就要取好了(大概是终于知道怎么改类名)。会添加文件之后,把原来的三个类的.cpp和.h文件包含进来就好了,能出结果这步问题不大,(不过后来为了实现信号和槽之类的功能,还是改成了继承与QObject的类),这一步主要的问题是算式有误的报错问题。下面是主要的代码:

Calculator.cpp

#include "scaner.h"
#include "printer.h"
#include "calculation.h"
#include "calculator.h"
#include "ui_calculator.h"
#include <queue>
#include <QDebug>
#include <string>
#include <iostream>
#include <QMessageBox>
using namespace std;
Calculator::Calculator(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Calculator)
{
    ui->setupUi(this);
}
Calculator::~Calculator()
{
    delete ui;
}
bool flag = 0;  //是否清空输入框
string s_input;   //用于计算的表达式
bool error_flag = 1;    //算式是否无误  
void Calculator::wrongInput(QString str)
{
    error_flag = 0;
    QMessageBox::warning(this, tr("ERROR"), str);
    ui->lineEdit->clear();
    s_input.clear();
}
void Calculator::on_pushButton_pointer_clicked()
{
    if(flag)
    {
        ui->lineEdit->clear();
        flag = 0;
    }
    s_input = s_input + ".";
    ui->lineEdit->setText(ui->lineEdit->text() + QObject::tr("."));
}
...
void Calculator::on_pushButton_backspace_clicked()
{
    ui->lineEdit->backspace();
    if(!s_input.empty())
    {
        s_input.pop_back();
    }   
} 
void Calculator::on_pushButton_escape_clicked()
{
    ui->lineEdit->clear();
    s_input.clear();
}
Scaner CScan;
Printer CPrint;
Calculation CCalculate;
double ans;
QString output;
queue<string> qs;
void Calculator::on_pushButton_equal_clicked()
{
    QObject::connect(&CScan, SIGNAL(sendError(QString)), this, SLOT(wrongInput(QString)));
    QObject::connect(&CCalculate, SIGNAL(sendError(QString)), this, SLOT(wrongInput(QString)));
    error_flag = 1;
    if(flag)
    {
        ui->lineEdit->clear();
    }
    s_input = s_input + "=";
    ui->lineEdit->setText(ui->lineEdit->text() + QObject::tr("="));
    qs = CScan.ToStringQueue(s_input);
    ans = CCalculate.CalculateStringQueue(qs, error_flag);
    if(error_flag)
    {
        ui->lineEdit->setText(output.setNum(ans, 'g', 10));
        s_input.clear();
    }
    flag = 1;
}

main函数里就只有show一下Calculator这个类的一个对象而已,计算都在Calculator里实现,具体就是和等号按钮相关的那个槽函数,然后这次直接由按钮转到槽,没有那么多的connect。计算什么的都是上次的修修补补,主要这次是多了个报错的弹窗。在Scaner和Calculation这两个类里都有发报错信号的函数,在Calculator类里面有个对应的报错的槽函数,connect写在哪里也是想了挺久,最后大概就是找了个不会报错的地方,然后测试的时候果然还是有迷之bug。不过qt creator的debug比dev c++的正常多了,调试的很顺利,代码逐渐完善成上面那样。最后还有一个迷之bug是,多次输入错误算式的话,它会重复报错好多次。举个例子来说,你输入一个等号,它报错,关掉弹窗再输一个等号,它再报错,这时你关掉弹窗它还会再报错一次,然后你还要关一次弹窗才能输入,依次递增。。。最后是试着在把等号的槽函数末尾加了两句取消关联,也就是那两个connect写成disconnect,然后就可以了耶,不是很懂为什么,反正可以正常报错了哈。然后还有一件事是报错之后,正常的算式它也报错。。。不过还好这次bug没有找很久,qt creator的调试还是很好用的,用cout也有地方可以看输出。下面是报错的效果(还有一个是数字的位数超过十位的报错),点ok之后会清空让你再次输入,第一阶段大概就是这样了:

阶段二:

这步是实现从键盘获取输入,感觉不会很难(没想到这也算一步),搜索一下大概很快就能解决,但还是意外地做得生无所恋。。。我试了一下,光标在输入框里的时候,它本来就能获取输入,大概是要重载一下输入的函数吧。搜索看了一些例子之后,大概觉得是要重载void QWidget::keyPressEvent(QKeyEvent *)这个函数,会响应不同按键,里面至少要包括界面那20个按键,大致是这样:

void Calculator::keyPressEvent(QKeyEvent *e)
{
    switch (e->key())
    {
        case Qt::Key_0:
            Calculator::on_pushButton_0_clicked();
            break;
        ...
    }
}

然而事实是我用键盘输入的时候,它只会对回车键进行响应,其他的数字什么有显示在输入框里,但是根本就不是我重载的那个函数干的,因为我在重载函数里设了一堆断点,调试的时候都是按完回车直接跳到回车键那个情况的断点,所以实际上后台计算的式子就只有一个等号,于是欣慰的正常报错。。。大概是刚改完迷之重复报错的bug,它就又来一个迷之输入的bug,于是就开始找原因找得怀疑人生,感觉老是碰到莫名其妙的问题,也是很无奈。大概是找资料找不到相似的问题,我就跑去看了其他用qt做的同学的,发现他们也是重载这个函数啊,简直无法理解。找不同找到郁闷,也没发现啥不一样啊,于是找bug找到怀疑人生的时候,就开始乱改试运气了。。。我把重载的函数换成一个系列的keyRelaeseEvent(大概是放开键盘按钮的时候响应),还是在输入框显示光标的时候从键盘输入,然后这次它正常响应了耶。但是啊,并没有什么用,原来那个不重载也能输入的还在,所以真实情况是按1会显示一个1,放开又会输入一个1进去。。。所以原来那个到底是为什么重载失败了啊。我又改回keyPressEvent,继续试来试去,偶然发现输入框没光标的时候它也可以输入耶,而且重载的函数居然正常调用,然后想起来其他同学的显示框用的部件好像是标签啊,唔,所以是因为这个不同吗。。。大概是因为我用的是单行(所以会响应回车)文本输入的部件,大概本来就有函数可以让它从键盘输入,所以重载的函数错掉了吧。我试了下,它还可以输入字母啥的,不过第四次要求只接收界面上的那几个,硬用这个好像很麻烦啊,那我还是用标签好了。唔,大概是知道vs code可以更改所有的匹配项,换掉所有的lineEdit还是挺快的。大概这就是第二阶段了,最后附上目前的界面效果(也就是给没颜色的标签上个色):

阶段三:

最后的阶段就是实现从文件的输入输出了,实现过程虽然算不上一帆风顺,但也还好了其实。搜索不久就大概确定用QFileDialog::getOpenFileName这个函数,它弹出来的目录窗口就和我们的系统的一样。然后原来摸索过怎么改类名,大概知道现在要再添加一个qt的设计师界面类,点击按钮就实例一个对象show出来就好。然而我写完点了按钮之后,它会闪退的。。。想起教程解释初始的main函数的时候:

#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

大概.exec这个函数就可以让界面一直显示,不像我们原来的c++程序跑完就退出,可是不幸的是,我继承的QMainWindow没有这个函数。。。搜索的解决方法说将窗口设置为模态啊啥,试了下没有成功,于是又改成继承自QDialog类。QDialog类默认的窗口按钮有个问号,按了下并没有反应,可惜没有找到怎么实现的方法,只找到了怎么去掉的(链接)。下面是界面最终的样子:

大概是觉得确认按完有些直接退出有些不够友好,于是又加了个弹窗。唔,也就只会这些其实,实际上还是很不友好,大概勉强完成作业要求,不是很想玩了。最后又花了点时间规范一下代码,然后传到Github上当黑历史。。。以上。

原文地址:https://www.cnblogs.com/mingyueanyao/p/5731223.html