这个示例展示了如何使用信号和插槽来实现计算器小部件的功能,以及如何使用QGridLayout来将子小部件放置到网格中。
该示例由两个类组成:
Calculator是计算器小部件,具有计算器的所有功能。
Button是用于每个计算器按钮的小部件。它源自QToolButton。
我们将从复习计算器开始,然后我们将看一下按钮。
详细讲解在:
https://doc.qt.io/qt-5/qtwidgets-widgets-calculator-example.html
介绍:
计算器中的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
当用户单击+或-按钮时,将调用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
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" =》 ÷
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和显示中的值。