实际上,我打算制作一个小样本来展示如何重载QPushButton。但后来我意识到它更简单,无需重载而是使用 lambdas 作为信号处理程序(自 Qt5 起支持):
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << QT_VERSION_STR;
// main application
QApplication app(argc, argv);
// setup GUI
QMainWindow qWin;
QGroupBox qBox;
QGridLayout qGrid;
QLineEdit qTxt;
qGrid.addWidget(&qTxt, 0, 0, 1, 4);
enum { nCols = 4, nRows = 4 };
QPushButton *pQBtns[nRows][nCols];
const char *lbls[nRows][nCols] = {
{ "7", "8", "9", "-" },
{ "4", "5", "6", "+" },
{ "1", "2", "3", "*" },
{ "0", ".", "=", "/" },
};
for (int i = 0; i < nRows; ++i) {
for (int j = 0; j < nCols; ++j) {
pQBtns[i][j]
= new QPushButton(QString::fromLatin1(lbls[i][j]), &qWin);
qGrid.addWidget(pQBtns[i][j], i + 1, j);
}
}
qBox.setLayout(&qGrid);
qWin.setCentralWidget(&qBox);
qWin.show();
// install signal handlers
for (int i = 0; i < nRows; ++i) {
for (int j = 0; j < nCols; ++j) {
QObject::connect(pQBtns[i][j], &QPushButton::clicked,
// easy done with a lambda:
[&qTxt, &lbls, i, j]() {
qTxt.setText(qTxt.text() + QString::fromLatin1(lbls[i][j]));
});
}
}
// run application
return app.exec();
}
注意事项:
各个按钮的特定信息实际上绑定到信号处理程序本身(而不是使其成为派生类的成员)。
我访问了 lbls 数组两次 - 一次用于 QPushButton 标签,另一次用于相应的信号处理程序。相反,我可以为后者使用QPushButton 标签本身。 (这是一个品味问题。)
-
信号处理程序的 lambda “绑定”其环境中各个按钮的所有特定信息:
- 对
qTxt 的引用
- 对
lbls 数组的引用
-
i 和 j 的值用于数组访问。
lambda 的签名必须与QPushButton::clicked 信号之一匹配,因此没有参数。返回类型实际上是缺失的,但在这种情况下,C++ 编译从返回表达式推断它。实际上,他们不是return 声明。因此,返回类型 void 也与 QPushButton::clicked 信号签名相匹配。
恕我直言,lambdas 和信号处理程序就像(希望)你的左右鞋一样适合。 Signal/slots(我过去使用过 sigc++)提供了绑定和隐藏参数或返回值所需的适配器的概念。它起作用了,但每次我不得不使用它时,我都在努力寻找正确的嵌套 - 它一团糟。所有这些问题都迎刃而解,因为 lambdas 可以提供任何适配器。
我看到的 lambda 的唯一困难(除了语法):您必须仔细考虑环境中引用(或指向)变量的生命周期(括号中的东西 [])。 (lambda 不是闭包——它可能不会根据自己的情况延长其环境的生命周期。)
在Windows 10(64位)上使用VS2013、Qt5.6编译测试: