The 4th part of the Calculator program _ Interface
题目链接:第六次作业(计算器第四步)
github链接:Calculator_1.6.2 第六次作业
工具:Qt Creator 5.6.0
讲道理好吧,终于有界面啦= =!!!还是先来说说上次的作业。第五次作业在完成之后各种缝缝补补(版本更迭!1.5.xxx),最大的问题就是偷懒的Scan.cpp里面读取表达式时遗留下来的坑。虽然之后线下自己做了修改,加上了些预处理,但是看到第五次作业结果惨不忍睹的正确率时,内心还是有点小崩溃的(早知道早点改了),另外Printer类的输出方法还是有点乱,各种调用有点理不清。
然后就是这次的作业,界面!version 1.6.2!
一开始是QT和MFC的选择,在各种百度之后,想想就短短几天,果断选择了简单方便的QT,虽然可能MFC不失为更好的选择...
接下来就是Qt的各种尝试历程
Part 1
在经过简单的Qt学习之后,就直接开始征程了。一开始,当然是恬不知耻(hhh~)的开启ui设计模式,各种拖动框框,东拼西凑,欧啦,一个纸面上的界面就完成啦!
接着只要对每一个按钮设置槽,再将第五次作业的各种类导入,当当当当,一个简单的计算器v1.6.0,Over~
Part 2
看完Part 1简单的两段话,是不是觉得步骤太过简单了= =,别急,下面就是不用ui文件这种粗暴的做法,而是代码的实现。
Calculator.h
class Calculator : public QDialog
{
Q_OBJECT
public:
explicit Calculator(QWidget *parent = 0);
~Calculator();
protected:
FileOperation *fo;
Printer *pr;
QLineEdit *editLine; // 输入框
QLabel *answerLine; // 结果框
// 按钮
QPushButton *button_0, *button_1, *button_2, *button_3, *button_4, *button_5, *button_6
, *button_7, *button_8, *button_9;
QPushButton *button_point, *button_add, *button_sub, *button_mul, *button_div, *button_equal;
QPushButton *button_lBracket, *button_rBracket;
QPushButton *button_file, *button_clear, *button_del;
string inputExp;
QString showAnswer;
double cacheAnswer;
bool equalFlag; // 是否已按下等号
private:
Ui::Calculator *ui;
private slots:
void button_0_clicked(); // 槽
void button_1_clicked();
void button_2_clicked();
void button_3_clicked();
void button_4_clicked();
void button_5_clicked();
void button_6_clicked();
void button_7_clicked();
void button_8_clicked();
void button_9_clicked();
void button_point_clicked();
void button_add_clicked();
void button_sub_clicked();
void button_mul_clicked();
void button_div_clicked();
void button_equal_clicked();
void button_file_clicked();
void button_clear_clicked();
void button_del_clicked();
void button_lBracket_clicked();
void button_rBracket_clicked();
};
Calculator.cpp
Calculator::Calculator(QWidget *parent) :
QDialog(parent),
ui(new Ui::Calculator)
{
ui->setupUi(this);
this->setWindowTitle(QStringLiteral("计算器"));
this->setFixedSize(300, 230);
this->setStyleSheet("background-image:url(D:/Qt_Creator_Projects/Calculator_2/bg_6.jpg)");
fo = NULL;
pr = new Printer();
cacheAnswer = 0;
equalFlag = false;
editLine = new QLineEdit("0");
...
button_add->setFixedSize(51, 56);
button_file->setToolTip(QStringLiteral("文件读写操作"));
button_clear->setFixedSize(51, 56);
QGridLayout *mainLayout = new QGridLayout(this);
mainLayout->addWidget(editLine, 0, 0, 1, 5); // 布局
...
connect(button_0, SIGNAL(clicked()), this, SLOT(button_0_clicked()));
...
setLayout(mainLayout);
}
void Calculator::button_0_clicked()
{
if (editLine->text() == "0" || equalFlag)
{
if (equalFlag)
{
equalFlag = false;
}
editLine->setText(QString('0'));
}
else
{
editLine->setText(editLine->text() + QString('0'));
}
}
...
void Calculator::button_add_clicked()
{
if (equalFlag)
{
equalFlag = false;
editLine->setText(showAnswer);
}
editLine->setText(editLine->text() + QString('+'));
}
...
void Calculator::button_equal_clicked()
{
if (equalFlag)
{
editLine->setText(QString('0'));
}
else
{
answerLine->setText(editLine->text() + QString(" = "));
editLine->setText(editLine->text() + QString('='));
inputExp = editLine->text().toStdString();
cacheAnswer = pr->printResult(inputExp);
showAnswer = QString::number(cacheAnswer, 10, 12); // 默认至多保留12位小数
int pointIndex = showAnswer.indexOf(".");
bool afterPointNonZeroInt = false; // 小数点后是否存在非零整数
int afterPointFirstNonZeroIntIndex = pointIndex;
for (int i = pointIndex; i < showAnswer.length(); i++)
{
if (showAnswer[i] >= '1' && showAnswer[i] <= '9')
{
afterPointNonZeroInt = true;
afterPointFirstNonZeroIntIndex = i;
break;
}
}
int precision = showAnswer.indexOf("0", afterPointFirstNonZeroIntIndex);
if (precision != -1 && precision > pointIndex)
{
if (!afterPointNonZeroInt) // 若为整数(.000....),则截取至(不含)小数点
{
showAnswer = showAnswer.left(pointIndex);
}
else
{
showAnswer = showAnswer.left(precision);
}
}
answerLine->setText(answerLine->text() + showAnswer);
}
equalFlag = true;
}
void Calculator::button_file_clicked()
{
fo = new FileOperation();
fo->show();
}
void Calculator::button_clear_clicked()
{
editLine->setText(QString('0'));
answerLine->setText(QString('0'));
}
void Calculator::button_del_clicked()
{
if (equalFlag)
{
equalFlag = false;
editLine->setText(QString('0'));
answerLine->setText(QString('0'));
}
else
{
QString qs = editLine->text();
int len = qs.length();
if (len == 1)
{
editLine->setText(QString('0'));
}
else
{
editLine->setText(qs.left(len - 1));
}
}
}
眼花缭乱有没有!想砸了它有没有!要多少个按钮就定义了多少个PushButton和槽!
不过程序还是不难理解的。按下按钮后对应显示区显示对应符号,在deadline更新到5号之后,多出来的两天也让我有时间将自己的想法多修修补补,比如,"="按下后,在v1.6.1中是固定显示3位小数的,包括"x.000","x.xxx(xxx...万分位开始被截断)"的情况,后来在v1.6.2中改进,寻找最佳的精度(默认至多不超过12位小数)并显示到显示区。再如,v1.6.2比起v1.6.1也加上了图标、背景等等。
Part 3
在Calculator中,File按钮对应的是打开文件操作窗口,即第五次作业所要求的文件读写,该部分写在FileOperation类中
FileOperation.h
class FileOperation : public QDialog
{
Q_OBJECT
public:
explicit FileOperation(QWidget *parent = 0);
~FileOperation();
protected:
Printer *pr;
QLabel *input_1;
QLabel *input_2;
QLineEdit *inputAddrLine;
QLineEdit *outputAddrLine;
QPushButton *findAddr_1;
QPushButton *findAddr_2;
QPushButton *finish;
QPushButton *cancel;
string inputAddr;
string outputAddr;
signals:
void clicked();
private slots:
void findAddr_1_clicked();
void findAddr_2_clicked();
void finish_clicked();
void cancel_clicked();
};
FileOperation.cpp
FileOperation::FileOperation(QWidget *parent) :
QDialog(parent)
{
this->setWindowTitle(QStringLiteral("文件读写操作"));
this->setFixedSize(250, 150);
this->setStyleSheet("background-image:url(D:/Qt_Creator_Projects/Calculator_2/bg_6.jpg)");
pr = new Printer();
input_1 = new QLabel("the input file address :");
...
findAddr_1->setToolTip(QStringLiteral("选择输入文件路径"));
findAddr_2->setToolTip(QStringLiteral("选择输出文件路径"));
QGridLayout *fileDialogLayout = new QGridLayout(this);
fileDialogLayout->addWidget(input_1, 0, 0, 1, 4);
...
connect(findAddr_1, SIGNAL(clicked()), this, SLOT(findAddr_1_clicked()));
...
setWindowFlags(Qt::WindowStaysOnTopHint);
setLayout(fileDialogLayout);
}
void FileOperation::findAddr_1_clicked()
{
QString fil = QFileDialog::getOpenFileName(this, tr("Open txt"), ".", tr("txt Files(*.txt)"));
inputAddrLine->setText(fil);
}
void FileOperation::findAddr_2_clicked()
{
QString fil = QFileDialog::getOpenFileName(this, tr("Open txt"), ".", tr("txt Files(*.txt)"));
outputAddrLine->setText(fil);
}
void FileOperation::finish_clicked()
{
inputAddr = inputAddrLine->text().toStdString();
outputAddr = outputAddrLine->text().toStdString();
if (inputAddr.empty() || outputAddr.empty())
{
cout << "无效地址" << endl;
}
else
{
pr->printResult_f(inputAddr, outputAddr);
}
this->close();
}
void FileOperation::cancel_clicked()
{
this->close();
}
一个简单的文件操作界面就完成了,v1.6.1测试时发现当有文件路径为空时,点finished程序会gg,在v1.6.2的时候也做了简单的处理
Part 4
那么再说说这次的Qt之旅上的问题,除了上面涉及的之外,还有一点就是乱码的问题,百度上众云纷说,最后发现Qt5的QStringLiteral(const char*),用来从“字符串常量”创建QString对象的宏,避免了各种编码转换带来的乱码的问题。
再来就是qmake这玩意,并不是很理解,但有一点是,有时候你在往你的项目中添加文件时,没有加到项目中(有点懵逼...),导致出现无法解析的外部符号的error,再重新qmake之后,瞬间构建成功了。
还有就是遗留的Printer类的调用问题,加上暂未实现的提示对话框...等等等等
Part 5
这次的Qt的学习收获还是挺大的,对一个新的东西先有了大概上的了解,再加之以应用,总是能学到很多,当蹦出来的红色的error一个个消散时,当总算蹦出一个稍微能看点的界面时,总还是很激动的。
另外,感觉这次稍微多出来了点的时间,让自己闲着没事时不时想到了一些想法也能加以尝试、实现,再一次在自己的代码上不断的改进,看着它一点一点的改善也是有点小happy,而改进之路上遇到的新的问题,更多依靠百度加以理解最后解决。
毕竟,一路百度,一路前行(2333...)
最后,就不贴参考博客什么的了(毕竟问题太多参考得也多...),只附上运行图: