1. SLOT()
作为参数传递
Button *Calculator::createButton(const QString &text, const char *member)
{
Button *button = new Button(text);
connect(button, SIGNAL(clicked()), this, member);
return button;
}
Button *pointButton = createButton(tr("."), SLOT(pointClicked()));
// pointClicked() 声明为一个 private slots
void Calculator::pointClicked()
{
if (waitingForOperand)
display->setText("0");
if (!display->text().contains('.'))
display->setText(display->text() + tr("."));
waitingForOperand = false;
}
可以看到,createButton
有一个参数 member
,类型为 const char*
。在调用时直接将 pointClicked()
用 SLOT()
封装后传入。在 createButton()
内部,将 member
当做槽函数使用。
留意到 const char*
与 SLOT()
,不由猜想 SLOT()
的返回值为字符串。可以参考此处。
2. 特殊符号可以由八进制数体现
如上图,特殊符号有除号、乘号、正负号、平方号,代码中使用如下表示方法:
Button *changeSignButton = createButton(tr("\302\261"), SLOT(changeSignClicked()));
Button *divisionButton = createButton(tr("\303\267"), SLOT(multiplicativeOperatorClicked()));
Button *timesButton = createButton(tr("\303\227"), SLOT(multiplicativeOperatorClicked()));
Button *powerButton = createButton(tr("x\302\262"), SLOT(unaryOperatorClicked()));
\302\261
:\302(八进制) = 0xC2,\261 = 0xB1。0xC2B1 在十六进制转utf8中可以得到字符 ±
。
同理,\303\267 可以得出 ÷
;\303\227 可以得出 ×
;\302\262 可以得出 ²
。
这里八进制、十六进制,都是基于 utf8 编码,即将字符的 utf8 编码转为八进制数表示。
3. 通过转换获取信号发送者
void Calculator::unaryOperatorClicked()
{
Button *clickedButton = qobject_cast<Button *>(sender());
QString clickedOperator = clickedButton->text();
double operand = display->text().toDouble();
double result = 0.0;
if (clickedOperator == tr("Sqrt")) {
if (operand < 0.0) {
abortOperation();
return;
}
result = std::sqrt(operand);
} else if (clickedOperator == tr("x\302\262")) {
result = std::pow(operand, 2.0);
} else if (clickedOperator == tr("1/x")) {
if (operand == 0.0) {
abortOperation();
return;
}
result = 1.0 / operand;
}
display->setText(QString::number(result));
waitingForOperand = true;
}
已知发送信号为 Button
,通过 Button *clickedButton = qobject_cast<Button *>(sender());
强制转换得到发送信号的控件,再处理业务逻辑。
4. 计算顺序
在这个程序中,输入 1+2/3-4
结果等于 -2.33333
而非 -3
,采用了乘除号优先级高于加减号的逻辑处理。
疑问?
这个 demo 的 Button
只有 new
,并且没有指定 parent
,也没有 delete
,理论上讲应该存在内存泄漏。但是用工具 valgrind
貌似没有检测出来。
解答
代码中函数 Button *Calculator::createButton(const QString &text, const char *member)
的实现确实没有为 new Button
指定 parent
。但是在布局中,所有创建出来的 Button
都被加入到了 QGridLayout
中,
for (int i = 1; i < NumDigitButtons; ++i) {
int row = ((9 - i) / 3) + 2;
int column = ((i - 1) % 3) + 1;
mainLayout->addWidget(digitButtons[i], row, column);
}
并且窗口也是用了这个布局setLayout(mainLayout);
。
另外,这个程序并没有重新实现析构函数,也就是用了默认析构函数。说明内存问题由 Qt 提供的机制统一管理(释放)。
参考此处可以明白,在调用 setLayout
和 addWidget
这些操作时,子控件都会在函数内部被指定上 parent
,因此程序关闭时,parent
会逐一释放 children
的内存,不会造成内存泄漏。