程序综合设计实践 :QT实现计算器
程序综合设计实践 :用QT实现简易计算器及贷款计算
1,项目概述
该项目目标是设计开发一个支持连续计算的包括括号( ),求余%四则运算+ - * /的计算器 Calculator 以及贷款计算功能 Mortgage。
本程序为本人初学一周QT所作,才疏学亦浅,程序中绝对有意想不到的蜜汁bug(逃)欢迎大家评论区交流丫。
项目下载地址
通过单击按钮,输入并完成如4+5.21+6或 5*(8+16)-2 类似的连续计算,并将运算结果显示在输出文本框 lineEdit 中,计算的式子移至上方的 label 中。
支持负数,小数运算,并且精度为小数点后五位。支持简单的错误性检验。 CE 清空 Del 后退 More 切换至贷款计算。两个界面,贷款计算界面不做过多赘述。
2,设计步骤 (以下只举例 Calculator 界面)
界面设计部分
界面设计部分如图由
label (显示计算的式子)
lineedit (显示结果或者当前输入的式子)
以及各个按钮组成。
创建按钮的时候因为数目有点多,所以我们可以用数组保存创建的按钮 指针 ,后面就可以直接用 索引 对按钮进行操控。
QT支持用 css 渲染元素。如label->setStyleSheet("font-size:12px;color:grey;border-bottom:1px solid #f1f1f1;border-radius:5px;text-align:right;");
//from widget.cpp
setFixedSize(400,450); //固定窗口大小
setWindowIcon(QIcon(":/icon.png")); //设置icon
QLineEdit* lineedit = new QLineEdit(this); //创建 lineedit 对象
lineedit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //将该对象设为宽高可扩展
QLabel* label = new QLabel(this);
label->setText("请在下方输入要计算的式子..."); //设置文本内容
QString btnstr[22] = {"(", ")", "%", "CE", "Del",
"7", "8", "9", "+", "-",
"4", "5", "6", "*", "/",
"1", "2", "3", "More", "=",
"0", "."
};
auto that = this;
QPushButton* btn[22]; //创建22个按钮并用数组储存,并且绑定相应的槽函数。方便后面布局(偷懒
for(int i=0; i<22; i++){
btn[i] = new QPushButton(that);
btn[i]->setText(btnstr[i]);
btn[i]->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(btn[i],&QPushButton::clicked,that,[=](){
that->input(btnstr[i], lineedit, label);
});
}
//设置样式,美化
btn[4]->setStyleSheet("color:red;");
btn[18]->setStyleSheet("color:yellow;");
int cyellow[9] = {0,1,2,3,8,9,13,14};
for(int i=0; i<9; i++) btn[cyellow[i]]->setStyleSheet("color:#38d6d5;");
lineedit->setStyleSheet("color:#333;font-size:21px;font-weight:bolder;border:1px dashed #f1f1f1;border-radius:5px;text-align:right;");
label->setStyleSheet("font-size:12px;color:grey;border-bottom:1px solid #f1f1f1;border-radius:5px;text-align:right;");
lineedit->setAlignment( Qt::AlignRight);
label->setAlignment( Qt::AlignRight);
setStyleSheet("QPushButton {font-size:20px;font-weight:bold;color:ligrhtgrey;background-color: rgba(255, 255, 255, 0%);border:1px solid grey;border-radius:5px;} QPushButton:hover, QLabel:hover {font-size:25px;} Widget {background:qlineargradient(spread:pad,y1:1,y2:0,stop:0 #79f4f3,stop:1 #f8fefe);}");
setWindowTitle("Calculator");
//设置布局
QGridLayout* computelayout = new QGridLayout(this);
computelayout->addWidget(label, 0, 0, 1, 5);
computelayout->addWidget(lineedit, 1, 0, 1, 5);
computelayout->addWidget(btn[0], 2, 0, 1, 1);
computelayout->addWidget(btn[1], 2, 1, 1, 1);
computelayout->addWidget(btn[2], 2, 2, 1, 1);
computelayout->addWidget(btn[3], 2, 3, 1, 1);
computelayout->addWidget(btn[4], 2, 4, 1, 1);
computelayout->addWidget(btn[5], 3, 0, 1, 1);
computelayout->addWidget(btn[6], 3, 1, 1, 1);
computelayout->addWidget(btn[7], 3, 2, 1, 1);
computelayout->addWidget(btn[8], 3, 3, 1, 1);
computelayout->addWidget(btn[9], 3, 4, 1, 1);
computelayout->addWidget(btn[10], 4, 0, 1, 1);
computelayout->addWidget(btn[11], 4, 1, 1, 1);
computelayout->addWidget(btn[12], 4, 2, 1, 1);
computelayout->addWidget(btn[13], 4, 3, 1, 1);
computelayout->addWidget(btn[14], 4, 4, 1, 1);
computelayout->addWidget(btn[15], 5, 0, 1, 1);
computelayout->addWidget(btn[16], 5, 1, 1, 1);
computelayout->addWidget(btn[17], 5, 2, 1, 1);
computelayout->addWidget(btn[18], 5, 3, 2, 1);
computelayout->addWidget(btn[19], 5, 4, 2, 1);
computelayout->addWidget(btn[20], 6, 0, 1, 2);
computelayout->addWidget(btn[21], 6, 2, 1, 1);
逻辑设计部分
首先先将每个按钮都绑定对应的 槽函数
//from widget.cpp
for(int i=0; i<22; i++){
btn[i] = new QPushButton(that);
btn[i]->setText(btnstr[i]);
btn[i]->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(btn[i],&QPushButton::clicked,that,[=](){ //这里
that->input(btnstr[i], lineedit, label);
});
}
用户按下 = 按钮后,利用按钮的信号和槽调用 input() 函数
//from widget.cpp
void Widget::input(QString word, QLineEdit* lineedit, QLabel* label)
{
if(word == "="){
if(linetxt == "") label->setText("不能为空哦..."); // 首先判断表达式是否合法
else compute(lineedit, label); //合法,跳转到计算函数
}
else if (word == "More") { //切换贷款计算界面
this->hide();
emit calchangewindow();
}
else if (word == "CE") { //清空
linetxt = "";
labeltxt = "";
label->setText("");
lineedit->setText(linetxt);
}
else if (word == "Del") { //后退
QString tmp = "";
for (int i=0; i < linetxt.length()-1; i++)
tmp += linetxt[i];
linetxt = tmp;
lineedit->setText(linetxt);
}
else {
linetxt+=word; //输入为字符
lineedit->setText(linetxt);
}
}
计算时我们需要先将 中缀表达式 转化为 后缀表达式。
中缀表达式就是我们日常生活中正常使用的那种形如:a+b*c
后缀表达式就是形如abc*+,操作符在数字后面;
为什么有后缀表达式呢?
因为中缀表达式便于人们的理解与计算
但是后缀表达式更方便计算机的运算(如二叉树、堆栈的方法计算)
因此在读取一个中缀表达式后,我们得办法将他转化为后缀表达式。
那么怎么转化为后缀表达式呢?
我们可以用这种方法将中缀表达式转化为后缀表达式。
以下是节选自项目 backans.cpp 的实现将中缀表达式转化后缀表达式的函数
//from backans.cpp
string getback(string str)//获取后缀表达式的函数
{
char* middle = new char[100];
char* tmp = middle;
char* isFirst = tmp;
for (int i=0; i<str.length(); i++) {
*tmp = str[i]; //将 middle 所指向的字符串内容赋值为传入的 str ,同时保持 middle 指向首地址不变
tmp++;
}
char* back = new char[100]; //同上
char* backend = back;
stack<char> s;
s.push('#');
while (*middle)
{
if( ((middle == isFirst)&& *middle == '-' && Number(*(middle+1))) || ( *(middle-1) == '(' && *middle == '-' && Number(*(middle+1))) || Number(*middle))
{
*back = *middle; //判断是否为负数
back++, middle++;
}
else
{
if (Number(*(back - 1))) *back++ = ' '; //如果前一位是数字的话添加空格 用以区分
if (*middle == ')')//如果右括号的话,输出所有操作符直到遇到左括号,并抛弃相对应的一堆括号
{
while (s.top() != '(' && s.top() != '#')
{
*back = s.top();
s.pop();
back++;
*back++ = ' ';
}
middle++;
s.pop();//抛弃左括号
}
else if (*middle == '(')//遇到左括号,则进入栈
{
s.push(*middle); middle++;
}
else if (priority(*middle) > priority(s.top()))//如果栈内的操作符优先级高于栈外的优先级,则入栈
{
s.push(*middle); middle++;
}
else if (priority(*middle) <= priority(s.top()))
//如果栈内的操作符优先级低于或等于栈外的优先级,输出栈内的符号,并入栈栈外的符号
{
while (priority(*middle) <= priority(s.top()) && s.top() != '#') {
*back = s.top();
back++; //直到栈内的操作符为空 或者 低于栈外的优先级
s.pop();
*back++ = ' ';
}
s.push(*middle);
middle++;
}
}
}
while (isOpe(s.top()))//中缀表达式遍历完成,但是=栈中还有符号存在,一一出栈输出
{
if (Number(*(back - 1))) *back++ = ' ';
*back = s.top();
qDebug("%c",*back);
s.pop();
if(s.top() != '#'){
back++;
*back++ = ' ';
}
}
string tmpresult = ""; //后面这些由于某些蜜汁bug而做出的一些处理。。。请无视充满了妥协
string result = "";
int address = 0;
for (;backend<=back;backend++)
tmpresult += *backend;
while(Number(tmpresult[address]) || isOpe(tmpresult[address]) || tmpresult[address] == ' ')
result += tmpresult[address++];
return result;
}
转化为后缀表达式后怎么计算结果呢?
我们可以用这种方法将后缀表达式求值。
然后将结果打印至 lineEdit 即完成计算啦!
以下是节选自项目 backans.cpp 的实现计算后缀表达式的函数
//from backans.cpp
long double backans::result(string str)
{
string back = getback(str);
stack<long double> s;
for (int i=0; i<back.length(); ) {
if(!isOpe(back[i]) || (back[i] == '-' && Number(back[i+1]) )){ //将数字依次入栈
s.push(turnnum(back, i));
while (back[i] != ' ')
i++;
i++;
}
else {
long double a = s.top();
s.pop();
long double b = s.top();
s.pop();
s.push(Cauculate(back[i], b, a));//遇到符号时,取栈顶的第二个数和第一个数求解,并入栈
i+=2;
}
}
while (s.size() >= 2)//最终栈内存在的数大于2时,继续计算,直到只剩下一个数
{
long double a = s.top();
s.pop();
long double b = s.top();
s.pop();
s.push(Cauculate(back[back.length()-1], b, a));
}
//返回这个数字,既是最终结果
return s.top();
}
以上就是全部内容啦,希望能帮到您嘿嘿
程序综合设计实践 :QT实现计算器的更多相关文章
- .NET应用架构设计—面向查询的领域驱动设计实践(调整传统三层架构,外加维护型的业务开关)
阅读目录: 1.背景介绍 2.在业务层中加入核心领域模型(引入DomainModel,让逻辑.数据有家可归,变成一个完整的业务对象) 3.统一协调层Application Layer(加入协调层来转换 ...
- (转)EntityFramework之领域驱动设计实践
EntityFramework之领域驱动设计实践 - 前言 EntityFramework之领域驱动设计实践 (一):从DataTable到EntityObject EntityFramework之领 ...
- 大一C语言结课设计之《简单计算器》
/*===============================================*\ ** 设计目的:简单计算器,计算形如10*(20.2-30.6)+5.0/2的表达式值 ** 简 ...
- Java课程设计----仿Windows标准型计算器
JAVA课程设计 仿Windows标准型计算器(By Yanboooooooo) 一.团队介绍: 连燕波[组长]:网络1513学生. 张文博[组员]:网络1513学生. 二.项目git地址 码云项目地 ...
- 【DDD】领域驱动设计实践 —— UI层实现
前面几篇blog主要介绍了DDD落地架构及业务建模战术,后续几篇blog会在此基础上,讲解具体的架构实现,通过完整代码demo的形式,更好地将DDD的落地方案呈现出来.本文是架构实现讲解的第一篇,主要 ...
- 《响应式Web设计实践》学习笔记
原书: 响应式Web设计实践 目录: 第2章 流动布局 1. 布局选项 2. 字体大小 3. 网格布局 4. 混合固定宽度和流动宽度 第3章 媒介查询 1. 视口 2. 媒介查询结构 3. 内嵌样式与 ...
- 测试思想-测试设计 史上最详细测试用例设计实践总结 Part2
史上最详细测试用例设计实践总结 by:授客 QQ:1033553122 -------------------------接 Part1-------------------------- 方法:这里 ...
- 使用Axure RP原型设计实践07,注册判断
本篇实现注册页的一些功能.本项目是通过用户名和电子邮件进行注册的. 在本篇之前,在"使用Axure RP原型设计实践03,制作一个登录界面的原型"中已经对注册页做了基本的处理. 打 ...
- 使用Axure RP原型设计实践06,登录验证
登录验证主要功能包括: ● 用户名错误,提示无效用户名,用户名和密码文本框清空● 用户名存在,密码错误,提示密码错误,密码清空,焦点进入密码框● 用户名和密码都正确,验证通过 本篇接着"使用 ...
随机推荐
- CorelDRAW文件损坏的几种解决方法
以前做好的CorelDRAW文件突然打不开了,或者是死机.非法操作等原因造成CorelDRAW文件损坏,有时打开源文件发现一片空白,源文件保存损坏无法打开怎么办?此时不要着急,你可以试试以下几种办法帮 ...
- 在家看电影音效太差?Boom 3D帮你轻松升级
新片上映后,很多人都会选择去电影院观看,一是为了第一时间看到电影,还有一个原因就是电影院的音效往往可以让人身临其境,更好地感受电影的氛围.那如果在家刷片我们该怎么办呢? 我们可以使用Boom 3D这款 ...
- Vegas让人物回眸更有韵味的方法分享
"回眸一笑百媚生,六宫粉黛无颜色",是白居易在<长恨歌>中描述杨贵妃美貌的名句,这一句运用夸张的手法,反映了杨贵妃回眸时的娇媚横生,百般娇媚. 接下来,小编就教你用视频 ...
- 聊聊kafka-client的源码
一,感想 kafka 客户端代码很早以前 我就想研究借鉴一下,我前前后后至少阅读过三遍源码,我发现我看不下去,不知道为啥这么写,在次期间,我也参考了很多的网上的源码分析,我发现自己依然一知半解的, 慢 ...
- C++高级程序员进阶之路
一.自学成为高级程序员推荐看的书: 1.c语言基础 <c primer Plus>.<c和指针>.<C专家编程> 2.C++语言基础 <C++ Primer& ...
- Java基础教程——Socket编程
Socket通常也称作"套接字",用于描述IP地址和端口,可以用来实现不同虚拟机或不同计算机之间的通信. --百度百科 套接字允许应用程序插入到网络中,并与插入到网络中的其他应用程 ...
- tar解压提示:tar (child): 无法连接至 xxxx: 解析失败
如图提示: 错误原因:由于压缩文件中含有冒号导致 解决办法: 使用tar命令的–force-local选项
- Spring Boot 项目瘦身指南,瘦到不可思议!129M->1.3M
之前在 从使用传统Web框架到切换到Spring Boot后的总结 中提到关于 Spring Boot 编译打包,Spring Boot 应用程序不用额外部署到外部容器中,可以直接通过 Maven 命 ...
- 【Usaco 2009 Gold】JZOJ2020年9月19日提高B组T3 头晕的奶牛
[Usaco 2009 Gold]JZOJ2020年9月19日提高B组T3 头晕的奶牛 题目 Description 奶牛们发现,在农场里面赛跑是很有趣的一件事.可是她们一旦在农场里面不断地转圈,就会 ...
- android studio报butterknife错误
Error:Execution failed for task ':shipper:javaPreCompileDebug'.> Annotation processors must be ex ...