从零开始自制计算器 您所在的位置:网站首页 单片机编码软件 从零开始自制计算器

从零开始自制计算器

#从零开始自制计算器| 来源: 网络整理| 查看: 265

1 概述

这个是仿照Win10自带的计算器制作的简化版本,是用Qt做的,直接把整个表达式输入然后得出计算结果。

主要分为三部分:

界面:就是看到的计算器,包括标题栏,中间的输出框,还有各个按键事件处理:就是处理对应的鼠标与键盘事件表达式处理:就是处理整个输入的字符串,返回计算的结果,当然这个还支持错误判断功能2 新建工程

选择Widgets Application:

一般只需MinGW:

这里默认即可,名字可以随便改。

3 界面3.1 按键

按键的话,基本上按着改就可以了,改布局,改颜色,改字体。

首先先打开.ui文件:

3.1.1 Grid Layout

添加一个Grid Layout并调整好大小。

3.1.2 按键

拖入Push Button作为按键,sizePolicy属性那里水平和垂直属性都选择Expanding:

3.1.3 颜色与字体

调整好颜色,设置styleSheet与字体:

参考styleSheet如下:

border:1px groove rgb(220,220,220); background-color:rgb(243,243,243);

字体:

3.1.4 布局

复制制作好的Button,布好局。

3.1.5 改内容

这里不仅把里面的字符改变,还要把相应的对象名也改变:

再细调每一个按键,包括大小、字体与颜色,使总体效果更好:

数字要注意有"加粗"效果,符号的话尽量"精细"一点。

3.1.6 大小与间隔

整体修改大小,同时加上间隔。

调整好间隔,注意细节。

下面是Win10自带的计算器:

看到间隔了没?

想要的就是这种效果。

可以先运行看看:

两边的间隔的话一会配合widget的大小调整即可。

3.2 输出框

输出框很简单,就是一个QLineEdit。

3.2.1 QLineEdit

首先添加一个QLineEdit。

3.2.2 大小与颜色

调整好大小,设置好背景颜色。

參考qss如下:

border:0px groove rgb(243,243,243); background-color:rgb(245,245,245);3.2.3 其他

设置字体、只读和对齐。

3.3 标题栏

标题栏其实也很简单,一个QBoxLayout。

3.3.1 新建Horizontal Layout

3.3.2 添加细节

QLabel输入标题,两个QPushButton表示最小化与关闭,同时加入两个Spacer,让标题与左边空出一些距离。

其实就是模仿Win10的标题栏的效果。

这里就不做最大化了。因为涉及到按钮的重新排布问题,这个可以自己选择实现。

3.4 整体处理3.4.1 标题栏

把上一步做的标题栏移到合适的位置,同时删除自带的QMenuBar、QToolBar、QStatusBar。

3.4.2 细节调整

调整整体大小,同时添加透明度。

调整好后大概就那样,透明度这里选择了0.9。

4 事件处理4.1 光标事件4.1.1 标题栏4.1.1.1 拖动效果

首先把本来那个标题栏去掉。

setWindowFlags(windowFlags() | Qt::FramelessWindowHint);

再在protected中加入鼠标监听函数:

void mousePressEvent(QMouseEvent *); void mouseMoveEvent(QMouseEvent *);

私有成员中加入两个QPoint,分别表示当前窗口坐标与光标的坐标。

QPoint mousePoint; QPoint windowPoint;

第一个函数是鼠标按下时触发的,根据event->button()判断是否是左键,是的话获取mouse坐标,再设置窗口坐标。

当触发第二个函数时,即先判断是否按住左键不放,使用MainWindow的move方法移动窗口。

event->globalPos()获取坐标后减去原来光标的坐标得到窗口坐标的变化量,再用原坐标加上这个变化量。

void MainWindow::mousePressEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton) { mousePoint = event->globalPos(); windowPoint = frameGeometry().topLeft(); } } void MainWindow::mouseMoveEvent(QMouseEvent *event) { if(event->buttons() & Qt::LeftButton) { move(windowPoint + event->globalPos() - mousePoint); } } 4.1.1.2 最小化与关闭

这里以最小化为例,关闭也一样的,改一下函数调用即可。

在最小化按钮中右键选择Go to slot:

选择clicked():

添加一个最小化函数:

下面是关闭的函数:

4.1.2 按键

按键的鼠标事件包括两个:

光标移入与移出事件,为按键添加阴影,加深颜色等单击事件,在输出框中增减对应的字符4.1.2.1 移入与移出事件

这里的实现方式是通过事件过滤器实现的,增加一个eventFilter()函数:

bool eventFilter(QObject *,QEvent *);

首先通过event->type()判断事件类型,如果是光标悬停,再判断对应的各个对象增加阴影效果。

addNumButtonEffet()如下:

void MainWindow::addNumButtonEffect(QPushButton *button,QGraphicsDropShadowEffect *shadow) { shadow->setEnabled(true); button->setStyleSheet( "border:1px groove rgb(220,220,220);" "background-color:rgb(193,193,193);" ); }

这里QGraphicsDropShadowEffect *shadow事先初始化好了:

然后在添加事件过滤器:

这里可以对比一下有没有阴影的效果:

没有阴影:

加上阴影:

呃....这里可能是截图工具的问题,看不出来有多大的效果,但是直接在机器上看是有比较大的区别的,建议还是加上阴影。

4.1.2.2 单击事件

单击事件就是单击了某个按键然后用户可以在输出框中看到对应的反应。

依次选择按键,右键Go to slot:

选择clicked():

然后添加处理函数,这里实现了一个添加文本与清除焦点的函数,添加文本就是对应按键被光标单击后添加到输出框。单击后会把焦点保留在这个按钮上,键盘上敲空格默认会帮你"按一次"这个按钮,因此如果不清除焦点的话,在光标单击了某个按钮,比如7,按空格就会在输出框上输出7,光标单击了8后,按空格就会在输出框上输出8。

这里添加文本时还要注意默认的起提示作用的0。

void MainWindow::appendText(const QString &s) { if(ui->box->text() == "0") ui->box->setText(s); else ui->box->setText(ui->box->text()+s); } void MainWindow::appendTextAndClearFocus(QPushButton *button, const QString &s) { appendText(s); button->clearFocus(); } 4.2 键盘事件

键盘事件就是主要处理各个按键按下时的阴影与输出框添加输出。

键盘事件通过以下两个函数处理:

void keyPressEvent(QKeyEvent *); void keyReleaseEvent(QKeyEvent *);

第一个是按键按下时触发的,第二个是松开按键触发的。

4.2.1 添加阴影

在按键按下时添加上阴影与颜色加深效果:

通过event->key()依次判断各个键。

键位參考。

然后添加在keyRealeseEvent()中把对应的阴影去掉:

void MainWindow::keyReleaseEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_0: case Qt::Key_1: case Qt::Key_2: case Qt::Key_3: case Qt::Key_4: case Qt::Key_5: case Qt::Key_6: case Qt::Key_7: case Qt::Key_8: case Qt::Key_9: case Qt::Key_Plus: case Qt::Key_Minus: case Qt::Key_Asterisk: case Qt::Key_Slash: case Qt::Key_AsciiCircum: case Qt::Key_Percent: case Qt::Key_ParenLeft: case Qt::Key_ParenRight: case Qt::Key_BraceLeft: case Qt::Key_BraceRight: case Qt::Key_BracketLeft: case Qt::Key_BracketRight: case Qt::Key_Backspace: case Qt::Key_Space: case Qt::Key_Period: case Qt::Key_Escape: case Qt::Key_Equal: case Qt::Key_Return: removeNumButtonEffect(ui->num0,num0_shadow); removeNumButtonEffect(ui->num1,num1_shadow); removeNumButtonEffect(ui->num2,num2_shadow); removeNumButtonEffect(ui->num3,num3_shadow); removeNumButtonEffect(ui->num4,num4_shadow); removeNumButtonEffect(ui->num5,num5_shadow); removeNumButtonEffect(ui->num6,num6_shadow); removeNumButtonEffect(ui->num7,num7_shadow); removeNumButtonEffect(ui->num8,num8_shadow); removeNumButtonEffect(ui->num9,num9_shadow); removeSignButtonEffect(ui->plus,plus_shadow); removeSignButtonEffect(ui->minus,minus_shadow); removeSignButtonEffect(ui->mutiply,mutiply_shadow); removeSignButtonEffect(ui->divide,divide_shadow); removeSignButtonEffect(ui->pow,pow_shadow); removeSignButtonEffect(ui->percent,percent_shadow); removeSignButtonEffect(ui->parentheses,parentheses_shadow); removeSignButtonEffect(ui->parentheses,parentheses_shadow); removeSignButtonEffect(ui->brace,brace_shadow); removeSignButtonEffect(ui->brace,brace_shadow); removeSignButtonEffect(ui->bracket,bracket_shadow); removeSignButtonEffect(ui->bracket,bracket_shadow); removeSignButtonEffect(ui->backspace,backspace_shadow); removeSignButtonEffect(ui->blank,space_shadow); removeSignButtonEffect(ui->dot,dot_shadow); removeSignButtonEffect(ui->C,c_shadow); removeSignButtonEffect(ui->equal,equal_shadow); break; } }

这里之所以没有一个个按键去判断是因为有可能同时多个按键按下,然后同时松开后发现某个按键还存在阴影,因此统一当其中一个按键释放时去除所有按键的阴影。

4.2.2 添加输出

在输出框中添加输出,调用一个函数即可:

5 整体细节再处理5.1 淡入效果

看看效果:

这里实际使用了Qt的动画,针对透明度改变的动画。

void MainWindow::fadeIn(void) { QPropertyAnimation * changeOpacity = new QPropertyAnimation(this,"windowOpacity"); changeOpacity->setStartValue(0); changeOpacity->setEndValue(0.91); changeOpacity->setDuration(2500); changeOpacity->start(); }

第一行表示改变的是透明度,第二三行设置起始值与结束值,接下来设置动画时间(单位ms),然后开始动画。

5.2 设置固定尺寸

这里可以不设置最大尺寸,但一定要设置最小尺寸。

设置这个实际上禁止了拖拽去改变大小。

5.3 淡出效果

淡出效果与淡入效果类似。

不同的时需要添加计时处理,不能直接在exit(0)前调用fadeOut()函数,因为动画会在另一个线程启动,所以需要在主线程休眠指定秒数,等待淡出效果完成后,主线程再调用exit(0)。

void MainWindow::fadeOut(void) { QPropertyAnimation * changeOpacity = new QPropertyAnimation(this,"windowOpacity"); changeOpacity->setStartValue(0.9); changeOpacity->setEndValue(0); changeOpacity->setDuration(2500); changeOpacity->start(); QTime start = QTime::currentTime().addMSecs(2500); while(QTime::currentTime()

这里就不放淡出效果的图片了。

6 表达式处理

由于这是整个字符串作为表达式进行输入,需要先进行判断再计算,所以分为判断与计算两部分。

这里使用了一个新开的控制台工程,后面会把这个整合起来。

6.1 判断

使用了一个check类判断,由于只有10个数字按键,加减乘除、小数点、求余、求次幂、大中小括号、空格,所以可以分成这几类进行判断。

6.1.1 去除所有空格void removeAllBlank(void) { size_t i = 0; while((i = s.find(' ',i)) != string::npos) s.erase(i,1); }

首先把所有空格去除,避免之后的判断。

6.1.2 分类判断

把表达式中的所有字符分成5类:

数字小数点运算符号+ - * / ^ %左括号类( [ {右括号类) ] }

然后就是针对每个类型判断它的下一个字符是否是允许的类型,不是的话返回false。

比如碰上了一个( [ {,则它的下一个不能是运算符号或者小数点,当然允许-与+,因为有(-7) (+234)这种情况。

然后把这个符号保存下来判断后面是否是对应的右括号。

if(isLeftBrace(i)) { if(isSignOrDot(i+1)) { if(s[i+1] != '-' && s[i+1] != '+') return false; } braces.push(s[i]); }

整个判断函数如下:

bool valid(void) { if(isSignOrDot(0) || isRightBrace(0)) return false; len = s.size(); stack braces; for(size_t i=0;i

修改setText的内容,把结果传递过去。

7.2.1 数字格式

设置fixed格式,否则的话显示的是科学计数法,对小数位数有要求的话可以设置setprecision。

7.2.3 错误提示

这里出现错误时,输出"#",然后主程序读取到就会提示"表达式错误,请重新输入。"。

还有除数为0的错误提示,这个要注意一下:

7.2.4 整合错误处理

可以考虑把错误处理整合过来,比如输入了一个点,不能继续输入点,输入了一个乘号或者除号不能再继续输入另一个符号:

8 打包发布8.1 Enigma Virtual Box

首先去下载Enigma Virtual Box。

8.2 添加环境变量

把Qt文件夹下的如图所示的bin添加到Path环境变量。

8.3 打包库文件

使用windeployqt打包,首先把程序调成release模式,运行一次,生成release的exe,然后把exe复制到一个单独的文件夹,再用命令行进入到这个文件夹,运行

windelpoyqt xxx.exe

这个命令把需要的dll复制到当前所在文件夹。

8.4 生成单个exe

打开Enigma Virtual Box,选择:

第一个选择release的exe,第二个选择打包之后的文件夹,然后选择添加文件,选择递归添加,添加上一步生成的所有文件(夹)。

这里选择压缩文件,然后选择压缩等待完成即可。

8.5 测试

点击运行:

大功告成!

9 源码Github码云10 参考链接Qt淡入Qt按键Qt标题栏事件过滤器Qt鼠标事件Qt延时处理Qt文件读写Qt打包成单文件11 最后

这个简单的计算器有很大的改进空间,比如可以添加各种"数":正弦函数、余弦函数、正切函数、反正弦函数、指数函数、对数函数、高阶导数、抽象函数、复合函数、心里没数等等。另外还可以改进矩形的按钮,可以改成圆角矩形或者椭圆形。对于阴影的处理可以添加淡入淡出效果。

最后就是磨砂,因为Win10的是有磨砂效果的,这个目前还不会。

最后再上几个图,看看效果(由于动图大小的限制只是简单的表达式):



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有