QT5.14.2 官方例子 - Qt Widgets 2: Calculator(计算器)

这个示例展示了如何使用信号和插槽来实现计算器小部件的功能,以及如何使用QGridLayout来将子小部件放置到网格中。

该示例由两个类组成:

Calculator是计算器小部件,具有计算器的所有功能。

Button是用于每个计算器按钮的小部件。它源自QToolButton。

我们将从复习计算器开始,然后我们将看一下按钮。

 

详细讲解在:

https://doc.qt.io/qt-5/qtwidgets-widgets-calculator-example.html

 

难点1:如何将由键盘按键提取的数字或运算符,有序地进行计算;还得考虑运算符的优先级,主要是(+, -, ×, or ÷).

介绍:

计算器中的MR,MS,MC,M+分别是什么意思

https://zhidao.baidu.com/question/574840419.html

 

这些变量,连同计算器显示的内容(一个QLineEdit),编码计算器的状态:

sumInMemory 包含存储在计算器内存中的值(使用MS、M+或MC)。

sumSoFar 存储到目前为止累计的值。当用户单击=时,sumSoFar将重新计算并显示在显示器上。清除所有将sumSoFar重置为零。

factorSoFar 在进行乘法和除法时存储一个临时值。

pendingAdditiveOperator 存储用户单击的最后一个加法运算符。

pendingMultiplicativeOperator 存储用户单击的最后一个乘法运算符。

当计算器期望用户开始键入操作数时,waitingForOperand为真。

加法运算符和乘法运算符被区别对待,因为它们有不同的先例。例如,1 + 2÷3被解释为1 +(2÷3),因为÷的优先级比+高。

理解:

由于运算符存在优先级,所以在计算时,得综合考虑前后两个运算符,就得将存储用户最后输入×, or ÷,还是+, -,的记录,简单理解:想计算1+2÷3, 不应该是(1+2)÷3 = 1, 而是应该是:1+(2÷3)=1.66667, 为了能按正确地优先级计算,比如到了下面的第四行,才能对前面输入的两步运算进行处理,这个时候就知道了是否存在两种优先级,以及按照优先级进行计算;

下表显示了当用户输入一个数学表达式时计算器状态的演变。

User Input

Display

Sum so Far

Add. Op.

Factor so Far

Mult. Op.

Waiting for Operand?

 

0

0

   

true

1

1

0

   

false

1 +

1

1

+

  

true

1 + 2

2

1

+

  

false

1 + 2 ÷

2

1

+

2

÷

true

1 + 2 ÷ 3

3

1

+

2

÷

false

1 + 2 ÷ 3 -

1.66667

1.66667

-

  

true

1 + 2 ÷ 3 - 4

4

1.66667

-

  

false

1 + 2 ÷ 3 - 4 =

-2.33333

0

   

true

一元运算符,如Sqrt,不需要特殊处理;它们可以立即应用,因为操作数在单击操作符按钮时已经知道。

 

以下是对上述逻辑过程的代码实现:

void Calculator::additiveOperatorClicked()
  {
      Button *clickedButton = qobject_cast<Button *>(sender());
      if (!clickedButton)
        return;
      QString clickedOperator = clickedButton->text();
      double operand = display->text().toDouble();

当用户单击+或-按钮时,将调用additiveOperatorClicked()槽。

在我们可以对clicked操作符进行实际操作之前,我们必须处理任何挂起的操作。我们从乘法运算符开始,因为它们的优先级比加法运算符高:

if (!pendingMultiplicativeOperator.isEmpty()) {
          if (!calculate(operand, pendingMultiplicativeOperator)) {
              abortOperation();
              return;
          }
          display->setText(QString::number(factorSoFar));
          operand = factorSoFar;
          factorSoFar = 0.0;
          pendingMultiplicativeOperator.clear();
      }

如果之前点击了x或÷,之后没有点击=,则显示的当前值就是x或÷运算符的右操作数,我们最终可以执行操作并更新显示。

if (!pendingAdditiveOperator.isEmpty()) {
          if (!calculate(operand, pendingAdditiveOperator)) {
              abortOperation();
              return;
          }
          display->setText(QString::number(sumSoFar));
      } else {
          sumSoFar = operand;
      }

如果前面单击了+或-,则sumSoFar是操作符的左操作数,而显示中的当前值是操作符的右操作数。如果没有挂起的加法运算符,则sumSoFar将被简单地设置为显示中的文本。

      pendingAdditiveOperator = clickedOperator;
      waitingForOperand = true;
  }

最后,我们可以处理刚刚被单击的操作符。因为我们还没有右边的操作数,所以我们将clicked操作符存储在pendingAdditiveOperator变量中。当我们有一个右操作数时,我们将应用这个操作,sumSoFar是左操作数。

 

下面是乘除法的槽函数:

 void Calculator::multiplicativeOperatorClicked()
  {
      Button *clickedButton = qobject_cast<Button *>(sender());
      if (!clickedButton)
        return;
      QString clickedOperator = clickedButton->text();
      double operand = display->text().toDouble();

      if (!pendingMultiplicativeOperator.isEmpty()) {
          if (!calculate(operand, pendingMultiplicativeOperator)) {
              abortOperation();
              return;
          }
          display->setText(QString::number(factorSoFar));
      } else {
          factorSoFar = operand;
      }

      pendingMultiplicativeOperator = clickedOperator;
      waitingForOperand = true;
  }

multiplicativeOperatorClicked()槽类似于additiveOperatorClicked()。在这里,我们不需要担心附加运算符,因为乘法运算符优先于附加运算符。

void Calculator::equalClicked()
  {
      double operand = display->text().toDouble();

      if (!pendingMultiplicativeOperator.isEmpty()) {
          if (!calculate(operand, pendingMultiplicativeOperator)) {
              abortOperation();
              return;
          }
          operand = factorSoFar;
          factorSoFar = 0.0;
          pendingMultiplicativeOperator.clear();
      }
      if (!pendingAdditiveOperator.isEmpty()) {
          if (!calculate(operand, pendingAdditiveOperator)) {
              abortOperation();
              return;
          }
          pendingAdditiveOperator.clear();
      } else {
          sumSoFar = operand;
      }

      display->setText(QString::number(sumSoFar));
      sumSoFar = 0.0;
      waitingForOperand = true;
  }

与additiveOperatorClicked()类似,我们从处理任何挂起的乘法和加法操作符开始。然后显示sumSoFar并将变量重置为零。必须将该变量重置为零,以避免对该值进行两次计数。

 

需要计算的时候,直接执行下列函数:

bool Calculator::calculate(double rightOperand, const QString &pendingOperator)
{
    if (pendingOperator == tr("+")) {
        sumSoFar += rightOperand;
    } else if (pendingOperator == tr("-")) {
        sumSoFar -= rightOperand;
    } else if (pendingOperator == tr("\303\227")) {
        factorSoFar *= rightOperand;
    } else if (pendingOperator == tr("\303\267")) {
        if (rightOperand == 0.0)
            return false;
        factorSoFar /= rightOperand;
    }
    return true;
}

私有的calculate()函数执行一个二进制操作。右操作数由右操作数给出。对于加法运算符,左操作数是sumSoFar;对于乘法运算符,左操作数是factorSoFar。如果出现除零的情况,函数返回false。

补充:(至于为何这么打印,不太清楚,知道的,可以请教下,哈哈)

字符串:"\303\227"  =》 × 

字符串:"\303\267" =》  ÷

 

难点2:MC,MS,MR,M+的表示:

void Calculator::clearMemory()
{
    sumInMemory = 0.0;
}

void Calculator::readMemory()
{
    display->setText(QString::number(sumInMemory));
    waitingForOperand = true;
}

void Calculator::setMemory()
{
    equalClicked();
    sumInMemory = display->text().toDouble();
}

void Calculator::addToMemory()
{
    equalClicked();
    sumInMemory += display->text().toDouble();
}

clearMemory()槽清除保存在内存中的和,

readMemory()将和显示为一个操作数,

setMemory()用当前和替换内存中的和,

addToMemory()将当前值添加到内存中的值。

对于setMemory()和addToMemory(),我们首先调用equalClicked()来更新sumSoFar和显示中的值。

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Command line: -prefix /home/liuyh/workspace/qt5.14.2-arm -opensource -confirm-license -release -strip -shared -xplatform linux-arm-gnueabi-g++ -optimized-qmake -c++std c++11 --rpath=no -pch -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcanvas3d -skip qtconnectivity -skip qtdatavis3d -skip qtdoc -skip qtgamepad -skip qtlocation -skip qtmacextras -skip qtnetworkauth -skip qtpurchasing -skip qtremoteobjects -skip qtscript -skip qtscxml -skip qtsensors -skip qtspeech -skip qtsvg -skip qttools -skip qttranslations -skip qtwayland -skip qtwebengine -skip qtwebview -skip qtwinextras -skip qtx11extras -skip qtxmlpatterns -make libs -make examples -nomake tools -nomake tests -gui -widgets -dbus-runtime --glib=no --iconv=no --pcre=qt --zlib=qt -no-openssl --freetype=qt --harfbuzz=qt -no-opengl -linuxfb --xcb=no -tslib --libpng=qt --libjpeg=qt --sqlite=qt -plugin-sql-sqlite -I/opt/tslib/include -L/opt/tslib/lib -recheck-all executing config test machineTuple + arm-linux-gnueabi-g++ -dumpmachine > sh: 1: arm-linux-gnueabi-g++: not found test config.qtbase.tests.machineTuple FAILED executing config test verifyspec + cd /home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/config.tests/verifyspec && /home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/qtbase/bin/qmake "CONFIG -= qt debug_and_release app_bundle lib_bundle" "CONFIG += shared warn_off console single_arch" 'QMAKE_LIBDIR += /opt/tslib/lib' 'INCLUDEPATH += /opt/tslib/include' -early "CONFIG += cross_compile" /home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/qtbase/config.tests/verifyspec + cd /home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/config.tests/verifyspec && MAKEFLAGS= /usr/bin/make clean && MAKEFLAGS= /usr/bin/make > rm -f verifyspec.o > rm -f *~ core *.core > arm-linux-gnueabi-g++ -c -O2 -march=armv7-a -mtune=cortex-a7 -mfpu=neon -mfloat-abi=hard -O2 -march=armv7-a -mtune=cortex-a7 -mfpu=neon -mfloat-abi=hard -pipe -O2 -w -fPIC -I/home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/qtbase/config.tests/verifyspec -I. -I/opt/tslib/include -I/home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/qtbase/mkspecs/linux-arm-gnueabi-g++ -o verifyspec.o /home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/qtbase/config.tests/verifyspec/verifyspec.cpp > make:arm-linux-gnueabi-g++:命令未找到 > make: *** [Makefile:172:verifyspec.o] 错误 127
06-09

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值