基于Qt5的计算器设计

2023-09-14 19:27:02

Qt5的信号与槽


描述:信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式(发布-订阅模式)。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。


信号的本质:信号是由于用户对窗口或控件进行了某些操作,导致窗口或控件产生了某个特定事件,这时候Qt对应的窗口类会发出某个信号,以此对用户的挑选做出反应。

槽的本质:在Qt中槽函数是一类特殊的功能的函数,在编码过程中也可以作为类的普通成员函数来使用。之所以称之为槽函数是因为它们还有一个职责就是对Qt框架中产生的信号进行处理。就是对信号作出的响应,对于打篮球的人来说,信号就是别人在起步投篮,你看到的这个动作就是信号,然后你会条件反射的想对其进行封盖,然后起跳,这个动作就是对应的槽
二者如何关联:使用connect函数关联。


函数原型:
QMetaObject::Connection QObject::connect(
const QObject *sender, PointerToMemberFunction signal,
const QObject *receiver, PointerToMemberFunction method,
Qt::ConnectionType type = Qt::AutoConnection);
参数:

  • sender: 发出信号的对象,也可以传入对象的指针
  • signal: 属于sender对象, 信号是一个函数, 这个参数的类型是函数
    指针, 信号函数地址
  • receiver: 信号接收者,也可以是对象指针
  • method: 属于receiver对象, 当检测到sender发出了signal信号,
    receiver对象调用method方法,信号发出之后的处理动作

// 参数 signal 和 method 都是函数地址, 因此简化之后的 connect() 如下:
connect(const QObject *sender, &QObject::signal,
const QObject *receiver, &QObject::method);

你实际使用过程中,可以直接使用对象,也可以使用对象指针。


计算器程序中的信号与槽

✨我们需要设计数字按键,加减乘除的按键,还有括号,小数点,等于号等等。

在这里插入图片描述

说明:del是删除一个位函数,delall是删除全部位函数,就是计算器的全部清除功能。is是等于号的按键槽函数

✨按钮的槽函数

void MainWindow::pushButton0()
{
    if(strin=="#")
        ui->textEdit1->clear();
   strin+="0";
   ui->textEdit1->textCursor().insertText("0");//textCursor()获取文本光标插入点的位置,后接入函数表示向光标后位置插入0
}

✨其他的数字一样。

✨括号函数的编写

//括号函数的编写

void MainWindow::pushButtonzuo()
{
    if(strin=="#")
        ui->textEdit1->clear();

    char* s=strin.toLocal8Bit().data();
    if (isdigit(s[strlen(s)-1]))//左括号前面为数字的话,则表示输入错误,前面只能是
        QMessageBox::about(this,"输入错误","左括号前面不是直接是数字");
    else
       { strin+="(";
        bracket=1;//表示前面有左括号
        ui->textEdit1->textCursor().insertText("(");}

}

其他括号一样。

✨加减乘除的编写

void MainWindow::pushButton_add()

{

  strin+="+";

  ui->textEdit1->textCursor().insertText("+");

  operror();

}

其他运算符一样

✨删除一位按钮的函数

//删除按钮
void MainWindow::pushButton_del()
{
   strin.chop(1);
   ui->textEdit1->textCursor().deletePreviousChar();
   if(strin=="#")
       ui->textEdit1->setText("0");
   else
        ui->textEdit1->setText(strin.mid(1));
}

✨删除全部位按钮的函数

void MainWindow::pushButton_delall()
{
     strin="#";
   if(strin=="#")
       ui->textEdit1->setText("0");
}

✨运算符检测函数

void MainWindow::operror(int num)

{

    char*s=strin.toLocal8Bit().data();

    if(!isdigit(s[strlen(s)-2])&&s[strlen(s)-2]!=')')

    {

        QMessageBox::about(this,"输入有误","您输入的双目运算符无左值");

        strin.chop(1);

        for(int i=1;i<=num;i++)

            ui->textEdit1->textCursor().deletePreviousChar();



    }

}

✨计算函数

double MainWindow:: cal(const QString& expression)
{

    QStack<double> values;//数值栈
    QStack<char> operatorstack;//操作符栈

    for(int i=0;i<expression.length();i++)
        {

            if(expression.at(i)=='(')
                 operatorstack.push(expression.at(i).toLatin1());//遇到左括号的话就入栈

            else if(expression.at(i) == ')')//如果遇到右括号的话,弹出操作符和操作数,直到遇到左括号。
                {
                     values.push(temp.toDouble());//压入
                    temp="";//复原
                    while(!operatorstack.isEmpty() && operatorstack.top() != '(')//只要不为空,直到左括号
                    {
                        char op = operatorstack.pop();//记录顶部的操作符
                        double num1=values.pop();//记录取出的第一个数
                        double num2=values.pop();//记录取出的第2个数
                        switch(op)//对不同的操作符做不同的处理
                        {
                            case '+': values.push( num1+num2);break;
                            case '-': values.push(num2-num1);break;
                            case '*': values.push(num1*num2) ;break;
                            case '/': if (num1==0)  QMessageBox::about(this,"除数非法","除数不能为0"); else values.push(num2/num1);break;
                            default: throw std::invalid_argument("无效的操作符");break;
                        }
                    }
                    operatorstack.pop();//结束之后把左括号弹出

                    }




            else if(expression.at(i) == '+'||expression.at(i) =='-')//按照优先级进行运算
               {
                         values.push(temp.toDouble());//压入
                         temp="";//复原
             if(!operatorstack.empty() && operatorstack.top() != '(' &&
                              (operatorstack.top() == '*' || operatorstack.top() == '/')) //如果现在的表达式比之前的低就要出栈
                        {
                             char op = operatorstack.top();//记录操作符
                             operatorstack.pop();//弹出操作符
                             double operand1 = values.pop();
                             double operand2 = values.pop();
                             switch(op)//对不同的操作符做不同的处理
                             {
                                 case '+': values.push(operand1+operand2);break;
                                 case '-': values.push (operand2-operand1);break;
                                 case '*': values.push(operand1*operand2) ;break;
                                 case '/': if (operand1==0)  QMessageBox::about(this,"除数非法","除数不能为0"); else values.push(operand2/operand1);break;
                                default: throw std::invalid_argument("无效的操作符");break;
                             }


                        }
               operatorstack.push(expression.at(i).toLatin1());//作为运算之后就把这个运算符进行压入

              }

         else if(expression.at(i) =="*"||expression.at(i) =="/")//一律压入栈
                  {
                    operatorstack.push(expression.at(i).toLatin1());
                    values.push(temp.toDouble());//压入
                    temp="";//复原
                  }

         else if(expression.at(i).isDigit() || expression.at(i)=='.')//如果是数字或者是小数点
                 {

                   temp=temp.append(expression.at(i));

                 }

         else
            {
                qWarning() << "无法识别的字符:" << expression.at(i);
                return 0.0;
           }




        }

    if (!temp.isEmpty())
    {
        values.push(temp.toDouble());
        temp = "";
    }

        // 执行剩余的操作
        while (!operatorstack.isEmpty())
        {
            char op = operatorstack.top();
            operatorstack.pop();
            if (values.size() < 2)
            {   qDebug()<<"value的大小为="<<values.size();
                qWarning() << "表达式格式不正确";
                return 0.0;
            }
            double operand11 = values.pop();
            double operand22 = values.pop();
            switch(op)//对不同的操作符做不同的处理
            {
                case '+': values.push(operand11+operand22);break;
                case '-': values.push (operand22-operand11);break;
                case '*': values.push(operand11*operand22) ;break;
                case '/': if (operand11==0)  QMessageBox::about(this,"除数非法","除数不能为0"); else values.push(operand22/operand11);break;
                default:throw std::invalid_argument("无效的操作符");break;
            }
        }

        // 最终栈中应该只有一个值,即表达式的结果
        if (values.size() == 1 && operatorstack.isEmpty())
        {
            double a=values.top();
            strin="#"+strin.setNum(a);
            return values.top();
        }
        else
        {   qDebug()<<"value的大小为="<<values.size();
            while (!values.isEmpty()) {
                qDebug()<<"数值栈的值为="<<values.pop();

            }
            qWarning() << "表达式格式不正确";
            return 0.0; // 处理格式不正确的情况,返回默认值或者适当的错误处理
        }

}

结果展示:

在这里插入图片描述
初始化的启动界面

在这里插入图片描述
在这里插入图片描述

更多推荐

程序猿比抓系列 - 搜索算法

必抓!搜索算法的深度剖析一:引言搜索算法是计算机科学中一类十分重要且常见的算法,它们在各个领域和应用场景中都有广泛的应用。搜索算法可以帮助程序员快速地在大规模的数据中找到目标元素,从而提高程序的效率和准确性。对于一个程序员来说,掌握各种搜索算法是必不可少的,可以帮助他们更好地解决实际问题,提高自己的编程水平。二:常见搜

搭建Docker开发环境_Linux

环境搭建文章目录环境搭建@[toc]DockerDocker运行权限Docker加速Docker容器创建Python版本切换版本工具RepoGit开发SDK代码拉取在线离线(推荐)Debian安装软件包编译打包问题技巧Dockersudoaptinstalldocker.ioDocker运行权限#添加dockergro

新的小伙伴加入,开始系统更新分享了

近几个月一直有一个好消息未跟大家分享,就是我们有新的小伙伴加入了,帅就不必说了,关键是对电控的理解那可不是一般的强,工程经验丰富,学术能力也是一等一的。我们有幸在一个公司工作,跟着一个企业导师学习技术,按照学校的叫法可以一定程度称为“同门”和“师兄弟”了。在我们的共事中,我也发现了他对电控领域相关的知识与技术有着深层次

(数组 / 字符串) 55. 跳跃游戏 ——【Leetcode每日一题】

❓55.跳跃游戏难度:中等给你一个非负整数数组nums,你最初位于数组的第一个下标。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标,如果可以,返回true;否则,返回false。示例1:输入:nums=[2,3,1,1,4]输出:true解释:可以先跳1步,从下标0到达下标1,然后再从

数据分析方法-对比分析和用户画像(文末送书)

🤵‍♂️个人主页:@艾派森的个人主页✍🏻作者简介:Python学习者🐋希望大家多多支持,我们一起进步!😄如果文章对你有帮助的话,欢迎评论💬点赞👍🏻收藏📂加关注+对比分析事出反常必有妖、没有对比就没有好坏如果单纯给你一个数字500或者-500,你可能两眼一懵,并不能得出什么有价值结论。那如果告诉你该公司是

【HarmonyOS】如何实现应用内引用HSP模块中ArkUI组件

【关键字】HSP开发、引入HSP模块中ArkUI组件【写在前面】在使用ArkTS开发HarmonyOS应用时,通常会定义一些公共组件或公共接口功能,此时可以将这些功能封装到HSP模块中,然后通过在HSP模块中导出组件或接口方式在其他模块中引用,可以实现应用内部代码与资源的共享。这里主要讲如何在entry模块中引用HSP

D. Boris and His Amazing Haircut

Problem-D-Codeforces问题描述:剪发,将数组a减为数组b,有m个剪刀,每个剪刀只可以用一次且可以在任意区间内剪发,将长度大于mi的减为mi。现在有m数组,数组元素是第i个剪刀可以剪到mi,问能否将a减为b。洛谷翻译:思路:一定是先减最长的,再减短的。在减的时候会将这个a数组渐渐减成多个数组,再对这些数

权限控制、Spring Security入门

权限控制认证和授权概念问题1:在生产环境下如果不登录后台系统就可以完成这些某些功能操作吗?答案显然是否定的,要操作这些功能必须首先登录到系统才可以。问题2:是不是所有用户,只要登录成功就都可以操作所有功能呢?答案是否定的,并不是所有的用户都可以操作这些功能。不同的用户可能拥有不同的权限,这就需要进行授权了。认证:系统提

【已解决】ModuleNotFoundError: No module named ‘torchnet‘

问题描述今天在复现Chinese-Chatbot-PyTorch-Implementation的时候出现了一些问题:包括且不限于ModuleNotFoundError:Nomodulenamed'torchnet',ModuleNotFoundError:Nomodulenamed'fire',ModuleNotFou

重磅!OpenAI将发布DALL·E 3,多模态ChatGPT来了!

9月21日凌晨,OpenAI在官网宣布,在今年10月份将通过API向ChatGPTPlus和企业版用户提供全新文本生成图片产品——DALL·E3。这意味着,ChatGPT在DALL·E3加持下将开启久违的多模态输出模式,用户通过文本就能直接在ChatGPT中生成各种类型图片。例如,在ChatGPT中输入,生成一只可爱的

UE5学习笔记(1)——从源码开始编译安装UE5

目录0.前期准备1.Gitbashhere2.克隆官方源码。3.选择安装分支4.运行Setup.bat,下载依赖文件5.运行GenerateProjectFiles.bat生成工程文件6.生成完成,找到UE5.sln/UE4.sln7.大功告成0.前期准备0.1在windows的话,建议装一个Gitbash,同时还要有

热文推荐