程序综合设计实践 :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,登录验证
登录验证主要功能包括: ● 用户名错误,提示无效用户名,用户名和密码文本框清空● 用户名存在,密码错误,提示密码错误,密码清空,焦点进入密码框● 用户名和密码都正确,验证通过 本篇接着"使用 ...
随机推荐
- 实用简易的U盘修复工具推荐
如果我们的U盘出现可以读取,但不能打开,或是提示格式化的情况,那可能是U盘硬件出现了问题.U盘内部部件损坏就只能维修了,如果是u盘出现逻辑错误,常用的解决方法就是到网上下载一个u盘修复工具,对u盘进行 ...
- Idea中如何导入jar包
1.首先在idea左上角找到" File ",然后找到 "Project structure" 2.接着选择 " java ",选择后接着会 ...
- Linux安装MySQL5.7(CentOS)
1.下载解压 1.1 MySql 5.7.26下载地址: https://dev.mysql.com/downloads/mysql/5.7.html#downloads 1.2 解压 tar -xv ...
- php项目使用git的webhooks实现自动部署
前言 在项目开发中使用git进行代码的管理,每次完成更改上传代码后,还需要登录服务器将代码拉取下来.现在git服务器(gitee/gitlab/github)都会有Webhooks功能,以实现在向gi ...
- linux查看内存及磁盘使用情况
1.查看当前目录 命令: df -h (统一每个目录下磁盘的整体情况) 2.查看指定目录 在命令后直接放目录名,比如查看"usr"目录使用情况: 命令: df ...
- HOOK API函数跳转详解
原文链接:https://blog.csdn.net/cosmoslife/article/details/7670951 结合课件逆向11分析
- 推荐系统实践 0x0b 矩阵分解
前言 推荐系统实践那本书基本上就更新到上一篇了,之后的内容会把各个算法拿来当专题进行讲解.在这一篇,我们将会介绍矩阵分解这一方法.一般来说,协同过滤算法(基于用户.基于物品)会有一个比较严重的问题,那 ...
- Fiddler 4 (利用Fiddler模拟恶劣网络环境)
1.模拟弱网环境 打开Fiddler,Rules->Performance->勾选 Simulate Modem Speeds,勾选之后访问网站会发现网络慢了很多 解决办法去掉勾选的地方网 ...
- PyQt(Python+Qt)学习随笔:QTreeWidgetItem项是否禁用disable、隐藏isHidden和允许选中isSelected
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 树型部件QTreeWidget的项QTreeWidgetItem对象具有是否禁用disable.是否 ...
- 第13.1节 关于Python的异常处理
Python的异常网上有很多资料介绍,老猿就不再细说,在这里老猿只挑几件老猿认为重要的内容介绍一下. 一. 异常处理完整语法 异常处理的完整语法语法如下: try: - except (异常1,-,异 ...