前情提要
上一篇实现了手搓一个简单的界面,这一篇通过设计功能+信号与槽制作一个满足四则运算的计算器。
即:
创建思路
先用设计功能画出UI界面,再利用栈的特性存储元素,然后用信号与槽处理逻辑,然后就可以了。
具体步骤
(1)创建项目
项目命名为calculator,并设定为widget,编译模式为qmake
(2)设计UI
打开设计栏,准备用鼠标拖动创建界面
可以看到已经创建了一个长宽都固定为40的按钮
复制出了相同的二十个按钮,然后把它们设成网格布局:先大概把它们排成五行四列,再全部选中选择右上角的网格布局。
再做屏幕上的输出框,使用input 里的lineEdit
然后把按钮改成正确的显示,而不是1
很好,现在UI界面已经差不多了,然后就可以修改按钮的命名了,因为命名现在是1-20,不是很方便
好的,现在用驼峰命名法改成自己想要的名字了
(3)逻辑实现
第一步:先做显示屏部分,思路是开一个字符串,用字符串存储点击的数字和符号
方法:在头文件的私有成员里加上QString类型
这个地方就要实现,点击哪个数哪个数就要出现在显示屏里,需要用到槽了
这个地方点击转到槽,然后在系统自动生成的成员函数里
void Widget::on_oneButton_clicked()
{
exprecision += "1";
ui->mainLineEdit->setText(exprecision);
}
写这个,原理就是让字符串多加一个“1”,然后把它增加到ui文件里的mainLineEdit里
现在跑一下代码:
1可以正常输入,现在我想把窗口名字改一下,可以在构造函数里输入:
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("计算器");
}
这个窗口大小不是很美观,我们可以改一下,也是在构造函数里改
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setMaximumSize(210,300);
this->setMinimumSize(210,300);
this->setWindowTitle("计算器");
}
宽度设置为210,高度设置为300,差不多的大小,很美观
但是输入框里的字不好看,我们可以再改一下字体:
QFont f("仿宋",14);
ui->mainLineEdit->setFont(f);
第一句是创建一个字体对象,第二句是把这个对象设置成输入框的字体
然后就是把0、2-9和+-*/、( )的成员函数全写一遍
好,下面是测试结果:
接下来再实现clear功能:
void Widget::on_clearButton_clicked()
{
exprecision.clear();
ui->mainLineEdit->clear();
}
再实现delete功能:
void Widget::on_deleteButton_clicked()
{
exprecision.chop(1);
ui->mainLineEdit->setText(exprecision);
}
测试是动态的,就不放图了。
现在我觉得“=”号按钮的背景颜色不好看,我还想改一下背景颜色,所以我在构造函数里又写了一个改变按钮背景颜色的代码
ui->equalButton->setStyleSheet("background:white");
现在只剩下实现计算逻辑了。
在开篇时已经提到了,用栈存储元素,实现计算。
void Widget::on_equalButton_clicked()
{
QStack<int> s_num,s_opt;
char opt[128]={0};
int i=0,tmp=0,num1,num2;
//把QString转换成char *
QByteArray ba;
ba.append(expression.toUtf8()); //把QString转换成QByteArray
strcpy(opt,ba.data());
while(opt[i]!='\0'||s_opt.empty()!=true)
{
if(opt[i]>='0'&&opt[i]<='9')
{
tmp=tmp*10+opt[i]-'0';
i++;
if(opt[i]<'0'||opt[i]>'9')
{
s_num.push(tmp);
tmp=0;
}
}
else //操作符
{
if(s_opt.empty()==true||Priority(opt[i])>Priority(s_opt.top())||(s_opt.top()=='('&&opt[i]!=')'))
{
s_opt.push(opt[i]);
i++;
continue;
}
if(s_opt.top()=='('&&opt[i]==')')
{
s_opt.pop();
i++;
continue;
}
if(Priority(opt[i])<=Priority(s_opt.top())||(opt[i]==')'&&s_opt.top()!='(')||(opt[i]=='\0'&&s_opt.empty()!=true))
{
char ch=s_opt.top();
s_opt.pop();
switch(ch)
{
case '+':
num1=s_num.top();
s_num.pop();
num2=s_num.top();
s_num.pop();
s_num.push(num1+num2);
break;
case '-':
num1=s_num.top();
s_num.pop();
num2=s_num.top();
s_num.pop();
s_num.push(num1-num2);
break;
case '*':
num1=s_num.top();
s_num.pop();
num2=s_num.top();
s_num.pop();
s_num.push(num1*num2);
break;
case '/':
num1=s_num.top();
s_num.pop();
num2=s_num.top();
s_num.pop();
s_num.push(num1/num2);
break;
}
}
}
}
ui->mainLineEdit->setText(QString::number(s_num.top()));
expression.clear();
}
int Widget::Priority(char ch)
{
switch(ch)
{
case '(':
return 3;
case '*':
case '/':
return 2;
case '+':
case '-':
return 1;
default:
return 0;
}
}
利用这段代码最后就可以实现一个简陋的计算器。
篇末总结
这项工程主要包括:ui的拖动及控件名的修改,按钮点击后在输入框的显示,等于号点击后的计算逻辑。
ui拖动和按钮显示比较好实现,核心点在于通过一个QString类的expression增删改,然后重新输出在输入框中。
计算逻辑要用到栈将数字和符号拆开处理,利用栈的特性将数据存储起来。
这个项目的收获:
1. 知道了Qt如何创建ui界面
2. 知道了设计栏的属性工具栏部分属性的作用
3. 知道Qt的面向对象非常重要,库函数都是利用面向对象实现的
4. 知道了一些库函数的用法,明白了Qt的基本使用逻辑,即利用Qt提供的库函数完成对界面的修改,对逻辑的实现,语法都是面向对象
5. 更深入地理解了槽,知道槽是一个函数,是在按钮类触发某个条件后要进行的动作。