程序综合设计实践 :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中的3D线条表现方法
CorelDRAW图形设计工具的最优势之一是其强大的交互式工具. 调和工具就是这样一种互动性很强的工具,从表面上看来可能不是那么突出,但功能是真的强啊!一旦发现它的潜力,它很快就会成为经验丰富的Cor ...
- 详解FL Studio压缩器——Fruity Limiter(下)
Hello!小伙伴们又见面啦-接上一篇,本篇咱们继续讲解音乐编曲软件FL Studio20压缩器内容. 包络"ENVELOPE"中包含三个旋钮,它们都有什么作用呢?一起来揭晓吧! ...
- guitar pro系列教程(二十五):Guitar Pro教程之组织小节
上一章节我们讲述了关于Guitar Pro 7的主界面的相关功能的介绍,对于初学作曲,又是吉他的初学者,刚刚接触Guitar Pro时,很多的功能,符号,工具都市不熟悉的,这样在创作,使用的过程中就会 ...
- H5系列之video自己编写控制栏
首先来了解一下 video, video呢,是H5 的标签,别人说的 H5播放器,没错 就是他了,利用video标签,可以实现视频播放. 但是啊,你会发现,在不同的浏览器上,播放器的 控制栏,都是不一 ...
- mysql hash join
面阿里问到的. "mysql join的实现有几种方式?" "啥?不就一种吗?" 转载: 简单介绍:https://zhuanlan.zhihu.com/p/9 ...
- .nnmodel to .mlmodel
做项目时遇到.nnmodel 模型,不知道这是什么框架模型,没有头绪,抓住文件magic number是lzfse compressed, compressed tables. 在https://gi ...
- Django 的F查询与Q查询,事物
F查询 Django 提供 F() 来做这样的比较.F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值 示例1: 查询出卖出数大于库存数的商品 from ...
- ASP.Net Core 3.1 使用gRPC入门指南
主要参考文章微软官方文档: https://docs.microsoft.com/zh-cn/aspnet/core/grpc/client?view=aspnetcore-3.1 此外还参考了文章 ...
- Springboot核心注解
运行文中的代码需要在项目构建中引入springboot 相关依赖. ① @configuration configuration,用来将bean加入到ioc容器.代替传统xml中的bean配置.代码示 ...
- PyQt(Python+Qt)学习随笔:QScrollArea为什么不起作用未出现滚动条?
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 老猿在进行Scroll Area部件测试时,在下面的窗体中放置了一个Scroll Area部件,在部 ...