简体   繁体   English

如何对QPushButton进行子类化,以便信号将参数发送到插槽?

[英]How to subclass QPushButton so that the signal sends an argument to the slot?

I'm programming a little calculator in C++/Qt, and I'd like to avoid writing as much slots as there are QPushButton. 我正在用C ++ / Qt编写一个小计算器,并且我想避免编写与QPushButton一样多的插槽。 My teacher suggested me to subclass QPushButton and create a new signal. 我的老师建议我将QPushButton子类化并创建一个新信号。 So far I've written that : 到目前为止,我已经写过:

buttoncalc.h : buttoncalc.h:

class ButtonCalc : public QPushButton{

public:
    ButtonCalc(QString string);

signals:
    void sendValue(char c); 
};

But I don't know what to do with that. 但是我不知道该怎么办。 I should first change the char emmited depending on the string I pass in the constructor but I don't know where I should do it in my code. 我首先应该根据在构造函数中传递的字符串来更改所发出的char,但是我不知道在代码中应该在哪里执行。 Should I also redefine the clicked() signal of QPushButton ? 我还应该重新定义QPushButton的clicked()信号吗?

I'm a little lost here so I thank you for your answers. 我在这里有点迷路,非常感谢您的回答。

EDIT (some precisions) : The ButtonClass is used as replacement of QPushButton in the class that draws the calculator. 编辑(有些精度):ButtonClass用作替换绘制计算器的类中的QPushButton。 I need a way to use a single slot in that class. 我需要一种在该类中使用单个插槽的方法。 This slot should therefore have a way to know which button has been clicked. 因此,该插槽应具有一种方法来知道单击了哪个按钮。

Actually, I intended to make a small sample which should show how to overload QPushButton . 实际上,我打算制作一个小示例,该示例应显示如何重载QPushButton But then I realized it is even simpler without overloading but using lambdas for the signal handler (which are supported since Qt5): 但是后来我意识到,在没有重载的情况下使用lambda作为信号处理程序(从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();
}

Notes: 笔记:

  1. The specific info for the individual buttons is actually bound to the signal handler itself (instead making it a member of the derived class). 各个按钮的特定信息实际上绑定到信号处理程序本身(而不是使其成为派生类的成员)。

  2. I accessed the lbls array twice - once for the QPushButton label, again for the respective signal handler. 我访问了lbls数组两次-一次访问QPushButton标签,再次访问各自的信号处理程序。 Instead, I could have used the QPushButton label itself for the latter. 相反,我本可以为后者使用QPushButton标签本身。 (It's a matter of taste.) (这是一个品味问题。)

  3. The lambda for the signal handler "binds" all specific info for the individual buttons in its environment: 信号处理程序的lambda“绑定”环境中各个按钮的所有特定信息:

    • a reference to the qTxt qTxt的引用
    • a reference to the lbls array lbls数组的引用
    • the values of i and j for array access. 用于数组访问的ij的值。
  4. The signature of the lambda has to match the one of the QPushButton::clicked signal hence no parameters. Lambda的签名必须与QPushButton::clicked信号之一匹配,因此没有参数。 The return type is actually missing but in this case, the C++ compile infers it from the return expression. 返回类型实际上是丢失的,但是在这种情况下,C ++编译器从返回表达式中推断出它。 Actually, their is no return statement. 实际上,他们没有return声明。 So, return type void is inferred matching the QPushButton::clicked signal signature as well. 因此,推断返回类型void也与QPushButton::clicked信号签名相匹配。

  5. IMHO, lambdas and signal handlers are fitting together like (hopefully) your left and right shoe. 恕我直言,lambda和信号处理程序像(希望)您的左右鞋子一样装配在一起。 Signal/slots (I used sigc++ in the past) provided the concept of adapters needed for binding and hiding arguments or return values. 信号/插槽(我过去使用sigc ++)提供了绑定和隐藏参数或返回值所需的适配器的概念。 It worked but everytimes I had to use it I struggled in finding the correct nesting - it was a mess. 它可以工作,但是每次我不得不使用它时,我都在努力寻找正确的嵌套-这是一团糟。 All these problems are away since lambdas can provide any adapter. 由于lambda可以提供任何适配器,因此所有这些问题都已消除。

  6. The only difficulty with lambdas I see (beside of the syntax): you have to consider lifetimes of referenced (or pointed) variables in the environment (the thing in the brackets [] ) carefully. 我看到的lambda的唯一困难(除了语法之外):您必须仔细考虑环境(方括号[] )中引用(或指向)变量的生存期。 (A lambda is not a closure - it may not extend the lifetime of its environment according to its own.) (lambda不是闭包,它可能无法根据自身的情况延长其生存期。)

Compiled and tested with VS2013, Qt5.6 on Windows 10 (64 bit): 已在Windows 10(64位)上使用VS2013,Qt5.6进行编译和测试:

testQCustomButton.exe的快照

Use QSignalMapper which is designed for exactly this use case. 使用专门用于此用例的QSignalMapper The documentation includes the example so I will not repeat it here: 该文档包含该示例,因此在此不再赘述:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM