程序综合设计实践 :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,登录验证
登录验证主要功能包括: ● 用户名错误,提示无效用户名,用户名和密码文本框清空● 用户名存在,密码错误,提示密码错误,密码清空,焦点进入密码框● 用户名和密码都正确,验证通过 本篇接着"使用 ...
随机推荐
- JSX中写 switch case 进行判断
场景:根据后端返回的数据进行多条件渲染,三元表达式已不能满足条件. 代码: <span> {(() => { switch (record.generalRuleInfos[0]?. ...
- rocketmq的吞吐量为什么小于kafka
转载: https://www.jianshu.com/p/c474ca9f9430
- 数据共享-spring batch(9)上下文处理
目录 1 引言 2 开发环境 3 基于 Mybatis-plus 集成多数据源的数据库访问 3.1 pom 文件中引入 Mybatis-plus 3.2 配置及使用多数据源 4 ExecutionCo ...
- 【证书】curl 和 java 请求报证书错误
1. 说明: 以下:例子的域名因为工作环境的问题,被我拿自己的博客域名替代了,所以无法进行模拟测试,请珍重,哈哈! 2. 环境: centos:7.5 java jdk:1.8.0_74 3. cur ...
- 【Usaco 2009 Gold】JZOJ2020年9月19日提高B组T3 头晕的奶牛
[Usaco 2009 Gold]JZOJ2020年9月19日提高B组T3 头晕的奶牛 题目 Description 奶牛们发现,在农场里面赛跑是很有趣的一件事.可是她们一旦在农场里面不断地转圈,就会 ...
- JZOJ8月6日提高组反思
JZOJ8月6日提高组反思 又是愉快的没落的一天 被2020&2018暴打day2 一堆人AK-- T1 看到这个\(m\)只有100 就坚定了我打暴力的信心 离散化加暴力匹配 原本就想\(3 ...
- 基于struts2的记住账号密码的登录设计
一个简单的基于struts2的登录功能,实现的额外功能有记住账号密码,登录错误提示.这里写上我在设计时的思路流程,希望大家能给点建设性的意见,帮助我改善设计. 登录功能的制作,首先将jsp界面搭建出来 ...
- Jmeter(三十一) - 从入门到精通 - Jmeter Http协议录制脚本工具-Badboy4(详解教程)
1.简介 上一篇文章中宏哥给小伙伴或童鞋们介绍讲解了手动添加Variable list的值,而实际工作中Badboy为我们提供了Variable setter工具,让我们不再使用哪一种比较笨拙的方法了 ...
- msql语句
表相关语句: 创表相关 CREATE TABLE `Student`( `s_id` VARCHAR(20), `s_name` VARCHAR(20) NOT NULL DEFAULT '', `s ...
- 部署 Prometheus 和 Grafana 到 k8s
在 k8s 中部署 Prometheus 和 Grafana Intro 上次我们主要分享了 asp.net core 集成 prometheus,以及简单的 prometheus 使用,在实际在 k ...