如何子类化QPushButton以便信号向插槽发送参数?

时间:2017-03-25 08:41:54

标签: c++ qt

我用C ++ / Qt编写了一个小计算器,我想避免像QPushButton一样编写多少个插槽。 我的老师建议我继承QPushButton并创建一个新信号。 到目前为止,我已写过:

buttoncalc.h:

class ButtonCalc : public QPushButton{

public:
    ButtonCalc(QString string);

signals:
    void sendValue(char c); 
};

但我不知道该怎么做。我应该首先根据我在构造函数中传递的字符串更改char,但我不知道在代码中应该在哪里执行。我还应该重新定义QPushButton的clicked()信号吗?

我有点迷失在这里,所以我感谢你的答案。

编辑(一些精确): ButtonClass用于替换绘制计算器的类中的QPushButton。 我需要一种方法来使用该类中的单个插槽。因此,此插槽应该可以知道单击了哪个按钮。

2 个答案:

答案 0 :(得分:1)

实际上,我打算制作一个小样本,该样本应该显示如何重载QPushButton。但后来我意识到它更简单,没有重载但是使用lambdas作为信号处理程序(从Qt5开始支持):

// standard C++ header:
#include <iostream>

// Qt header:
#include <QApplication>
#include <QGridLayout>
#include <QGroupBox>
#include <QLineEdit>
#include <QMainWindow>
#include <QPushButton>

using namespace std;

int main(int argc, char **argv)
{
  cout << QT_VERSION_STR << endl;
  // main application
#undef qApp // undef macro qApp out of the way
  QApplication qApp(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 qApp.exec();
}

注意:

  1. 各个按钮的具体信息实际上绑定到信号处理程序本身(而不是使其成为派生类的成员)。

  2. 我访问了lbls数组两次 - 一次用于QPushButton标签,再次用于相应的信号处理程序。相反,我可以为后者使用QPushButton标签本身。 (这是品味问题。)

  3. 信号处理程序的lambda&#34;绑定&#34;其环境中各个按钮的所有特定信息:

    • qTxt
    • 的引用
    • lbls数组
    • 的引用
    • 数组访问的ij的值。
  4. lambda的签名必须与QPushButton::clicked信号匹配,因此没有参数。实际上缺少返回类型,但在这种情况下,C ++编译从返回表达式中推断出它。实际上,他们不是return陈述。因此,推断返回类型void也与QPushButton::clicked信号签名相匹配。

  5. 恕我直言,lambdas和信号处理程序像(希望)你的左右鞋一样装配在一起。 Signal / slots(我过去使用过sigc ++)提供了绑定和隐藏参数或返回值所需的适配器概念。它工作,但每次我不得不使用它我努力寻找正确的嵌套 - 这是一个烂摊子。由于lambda可以提供任何适配器,所有这些问题都消失了。

  6. 我看到lambda的唯一困难(除了语法):你必须仔细考虑环境中引用(或指向)变量的生命周期(括号[]中的事物)。 (lambda不是一个闭包 - 它可能根据它自己延长其环境的生命周期。)

  7. 在Windows 10(64位)上使用VS2013,Qt5.6进行编译和测试:

    Snapshot of testQCustomButton.exe

答案 1 :(得分:1)

使用专为此用例设计的QSignalMapper。文档包含示例,因此我不在此重复:

http://doc.qt.io/qt-5/qsignalmapper.html