一、实验目的和要求
1. 设计并实现计算器。
要求:在课后作业-03、课后作业-05的作业内容基础上
(1)增加图形交互功能。
(2)增加3个逻辑运算符 &&、||、 !,并能处理逻辑运算符和算术运算符的混合运算。
(3)增加容错功能,能进行异常处理。
二、实验环境
Qt 5.9
三、实验内容
在课后作业-03、课后作业-05的作业内容基础上
(1)增加图形交互功能。
(2)增加3个逻辑运算符 &&、||、 !,并能处理逻辑运算符和算术运算符的混合运算。
(3)增加容错功能,能进行异常处理。
四、实验过程
用文字、图(流程图等)、表格等方式记录实验过程中分析、设计工作。
4.1 任务定义和问题分析
实验第一个要求是添加三个逻辑运算符,还是原来的套路,比较运算符之间的优先级来进行计算。
第二个要求是增加图形界面,本来打算使用MFC编写,可是后来发现Qt要简单的多,最终就用Qt编写。
第三个要求是增加容错,应该就是在计算之前检查一下表达式是否有错误,防止程序崩掉。
4.2 数据结构的选择和概要设计
数据结构选择用栈
采用运算符优先级比较来计算表达式,设置一全局变量QString line来保存表达式,按下相应的按键后,将对应的符号添加到line中,按下等于号后,先检查一下表达式是否有误,然后进行计算,显示结果。
4.3 详细设计
1.输入表达式
为了将每一个符号添加到line中,设置void add_and_update()函数,将其与每个按键的信号相连,及每按一个键都会调用此函数,利用sender()函数来判断是哪一个按键发送的信号,将其对应的符号添加到line中。
2.计算输入的表达式
这里用了一个信号可以对应对个槽的机制,将‘=’按键与两个槽链接void add_and_update()和void caculate(),由于链接顺序不同,会先调用void add_and_update()将‘#’添加到line中;再调用void caculate()计算表达式。
3.容错
计算表达式前,先对表达式进行检查,若表达式有错弹出报错窗口并结束程序。
计算表达式时,若出现除数为零的情况,弹出报错窗口,结束程序。
计算过程中,若出现num栈为空但char_n栈不为空的情况,弹出报错窗口,结束程序。
4.逻辑运算符的计算:
与和或通过运算符优先级的比较来计算;
非直接在入栈计算,检测到符号“!”后,在num栈中取出一数,计算即可。
QString line; 用来保存用于计算的表达式。
QString line0; 用来保存用于显示的表达式。
QString history; 用来保存曾经正确计算的表达式,并将其显示出来。
QStack char_n; 用来保存字符。
QStack num; 用来保存数字。
QString s; 计算时将line赋值给它。
double result; 最后计算的结果。
void add_and_update(); 将运算符添加到line中。
void caculate(); 计算表达式。
bool check(); 检查表达式是否有误。
int getindex(char i); 得到对应字符的下标。
char getpriority(char i, char j); 通过下标来获取字符的优先级。
int hextobin(int i,int* n); 将十进制数转为二进制数。
int bintohex(int *p,int j) 将二进制数转为十进制。
int or_num(int j,int k); 对1,0进行或运算。
int and_num(int j,int k); 对1,0进行与运算。
int o_r(int j,int k); 对两个十进制数进行或运算。
int a_nd(int j,int k); 对两个十进制数进行与运算。
double caculator(char i, double j, double k);计算双目运算符
五、测试及结果分析
对各种数据运行程序和算法的结果记录和分析,并对错误所作的修改和结果。
5.1 实验数据
1+8/4-1!
5|8
9&(5+3)
9&1!
5.83.2-3
9/(4+8-12)
8-5
5.2 结果及分析
六、实验收获
熟悉了Qt的使用,对Qt图形界面有了一定的了解
七、附录(源代码)
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
protected slots:
void add_and_update();
void caculate();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
main.h
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include<Qstack>
#include<QString>
#include<iostream>
#include<cmath>
#include<QMessageBox>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->number0,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->number1,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->number2,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->number3,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->number4,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->number5,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->number6,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->number7,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->number8,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->number9,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->jia,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->jian,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->cheng,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->chu,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->zuokuohao,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->youkuohao,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->dengyu,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->dengyu,SIGNAL(clicked(bool)),this,SLOT(caculate()));
connect(ui->c,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->shanchu,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->And,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->Not,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->Or,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->dian,SIGNAL(clicked(bool)),this,SLOT(add_and_update()));
connect(ui->clearhistory,SIGNAL(clicked(bool)),this,SLOT(clear()));
setFixedSize(this->width(),this->height());//禁止改变窗体大小
}
Widget::~Widget()
{
delete ui;
}
QString line;
QString line0;
QString history;
QStack<char> char_n;
QStack<double> num;
QString s;
double result;
bool check()
{
QString error[8]={"/","*","+","-","&","|",")","!"};
QString error2[67]={"|&","&|","!|","!&","&-","&+","&*","&/","|+","|-","|*","|/","+&","+|","-&","-|","/|",
"/&","*&","*|","/*","*/","+-","-+","/-","-/","+/","/+","*+","+*","-*","*-","-)","(-",
"(+","+)","/)","(/","*)","(*","+-","-+","--","++","//","**","&&","||","!!","-.","+.",
"/.","*.","!.","&.","|.",".-",".+","./",".*",".!",".&",".|",".(",".)","(.",")."};
for(int i=0;i<8;i++)
if(line0.startsWith(error[i]))
return false;
for(int i=0;i<67;i++)
if(line0.contains(error2[i],Qt::CaseSensitive))
return false;
return true;
}
int getindex(char i)
{
switch (i)
{
case '+':
return 0;
case '-':
return 1;
case '*':
return 2;
case '/':
return 3;
case '(':
return 4;
case ')':
return 5;
case '&':
return 6;
case '|':
return 7;
case '#':
return 8;
default:
return -1;
}
}
char getpriority(char i, char j)
{
const char data[][9] =
{
{'>', '>', '<', '<', '<', '>', '>', '>', '>'},
{'>', '>', '<', '<', '<', '>', '>', '>', '>'},
{'>', '>', '>', '>', '<', '>', '>', '>', '>'},
{'>', '>', '>', '>', '<', '>', '>', '>', '>'},
{'<', '<', '<', '<', '<', '=', '<', '<', '0'},
{'>', '>', '>', '>', '0', '>', '>', '>', '>'},
{'<', '<', '<', '<', '<', '>', '>', '>', '>'},
{'<', '<', '<', '<', '<', '>', '<', '>', '>'},
{'<', '<', '<', '<', '<', '0', '<', '<', '='},
};
int c = getindex(i);
int d = getindex(j);
return data[c][d];
}
int hextobin(int i,int* n)
{
int j = 0;
while (i)
{
n[j] = i % 2;
i /= 2;
j++;
}
return j;
}
int or_num(int j,int k)
{
if (j==1||k==1)
{
return 1;
}
return 0;
}
int and_num(int j,int k)
{
if (j==1&&k==1)
{
return 1;
}
return 0;
}
int bintohex(int *p,int j)
{
int n = 0;
for (int i = 0; i < j; i++)
{
if (p[i]==1)
n += pow(2, i);
}
return n;
}
int o_r(int j,int k)
{
int n1[1000]={0}, n2[1000]={0};
int pos = hextobin(j, n1);
int pos2 = hextobin(k, n2);
if(pos>=pos2)
pos2=pos;
else {
pos=pos2;
}
int num[pos];
int h = 0;
for (int i = 0; i <pos; i++)
{
num[h] = or_num(n1[i], n2[i]);
++h;
}
return bintohex(num,pos);
}
int a_nd(int j,int k)
{
int n1[1000]={0}, n2[1000]={0};
int pos = hextobin(j, n1);
int pos2 = hextobin(k, n2);
if(pos>=pos2)
pos2=pos;
else {
pos=pos2;
}
int num[pos];
int h = 0;
for (int i = 0; i <pos; i++)
{
num[h] = and_num(n1[i], n2[i]);
++h;
}
return bintohex(num,pos);
}
double caculator(char i, double j, double k)
{
switch (i)
{
case '+':
return j + k;
case '-':
return j - k;
case '*':
return j * k;
case '/':
if(k==0)
return 1e10;
return j / k;
case '|':
return o_r(j,k);
case '&':
return a_nd(j,k);
default:
return 1e10;
}
}
void Widget::caculate()
{
if(!check())
QMessageBox::critical(this,"错误","输入的表达式有误!");
else
{
int i = 0;
char_n.push('#');
while (!s.isEmpty())
{
double data = 0;
bool is_data=false;
while (s[i].isDigit())
{
is_data=true;
QString m=s.mid(0,1);
data = data * 10 + m.toInt();
s.remove(0,1);
if(s[i]==".")
{
s.remove(0,1);
int pos=0;
int dex=0;
while (s[i].isDigit())
{
QString mn=s.mid(0,1);
pos = pos * 10 + mn.toInt();
dex++;
s.remove(0,1);
}
data+=pos/pow(10,dex);
}
}
if (is_data)
num.push(data);
if (s[i]=='!')
{
s.remove(0,1);
data=num.top();
num.pop();
num.push(!data);
}
if (!s[i].isDigit() )
{
char b = char_n.top();
char priority;
QString m=s.mid(0,1);
QChar *n=new QChar[1];
n=m.data();
char l;
l=n->toLatin1();
priority = getpriority(b, l);
switch (priority)
{
case '<':
char_n.push(l);
s.remove(0,1);
break;
case '=':
char_n.pop();
s.remove(0,1);
break;
case '>':
double q = num.top();
num.pop();
if(num.empty())
{
QMessageBox::critical(this,"错误","输入的表达式有误!");
return;
}
double w = num.top();
num.pop();
if(caculator(b, w, q)!=1e10)
num.push(caculator(b, w, q));
else
{
QMessageBox::warning(this,"警告","分母不能为零!");
return;
}
char_n.pop();
break;
}
}
}
result = num.top();
num.pop();
history+=line;
history+="=";
history+=(QString::number(result));
history+="\n";
ui->textBrowser->setText(history);
ui->lineEdit->setText(QString::number(result));
}
}
void Widget::add_and_update()
{
QPushButton *object=qobject_cast<QPushButton *>(sender());
QString name=object->objectName();
if(name=="number1")
{
line+="1";
line0+="1";
ui->label->setText(line);
}
if(name=="number2")
{
line+="2";
line0+="2";
ui->label->setText(line);
}
if(name=="number3")
{
line+="3";
line0+="3";
ui->label->setText(line);
}
if(name=="number4")
{
line+="4";
line0+="4";
ui->label->setText(line);
}
if(name=="number5")
{
line+="5";
line0+="5";
ui->label->setText(line);
}
if(name=="number6")
{
line+="6";
line0+="6";
ui->label->setText(line);
}
if(name=="number7")
{
line+="7";
line0+="7";
ui->label->setText(line);
}
if(name=="number8")
{
line+="8";
line0+="8";
ui->label->setText(line);
}
if(name=="number9")
{
line+="9";
line0+="9";
ui->label->setText(line);
}
if(name=="number0")
{
line+="0";
line0+="0";
ui->label->setText(line);
}
if(name=="chu")
{
line0+="/";
line+="÷";
ui->label->setText(line);
}
if(name=="cheng")
{
line0+="*";
line+="×";
ui->label->setText(line);
}
if(name=="jia")
{
line+="+";
line0+="+";
ui->label->setText(line);
}
if(name=="jian")
{
line+="-";
line0+="-";
ui->label->setText(line);
}
if(name=="And")
{
line+="&&";
line0+="&";
ui->label->setText(line);
}
if(name=="Not")
{
line+="!";
line0+="!";
ui->label->setText(line);
}
if(name=="Or")
{
line+="||";
line0+="|";
ui->label->setText(line);
}
if(name=="zuokuohao")
{
line+="(";
line0+="(";
ui->label->setText(line);
}
if(name=="youkuohao")
{
line+=")";
line0+=")";
ui->label->setText(line);
}
if(name=="dian")
{
line+=".";
line0+=".";
ui->label->setText(line);
}
if(name=="shanchu")
{
line.chop(1);
line0.chop(1);
ui->label->setText(line);
}
if(name=="c")
{
line=line0="";
ui->label->setText(line);
ui->lineEdit->setText("");
}
if(name=="dengyu")
{
s=line0+"#";
}
}
void Widget::clear()
{
history="";
ui->textBrowser->setText(history);
}