如何将参数从构造函数传递到插槽中?

How to transfer parameter from constructor into slot?

我正在用 Qt 做一个小练习。据我所知,slot save_clicked 只带来参数类型。那么如何将 userid 传输到文件 MyClass.cpp 中的插槽 save_clicked 以进行下面的处理?

MyClass.h

class MyClass : public QWidget
{
    Q_OBJECT

public:
    MyClass(QString userid, QString lastname, QString firstname, QWidget *parent = 0);
    ~MyClass();

public slots:
    void save_clicked(QString userid);

private:
    Ui::MyClass ui;
};

#endif // MYCLASS_H

MyClass.cpp

MyClass::MyClass(QString userid, QString lastname, QString firstname, QWidget *parent)
: QWidget(parent)
{
    ui.setupUi(this);
    ...........
    ...........
    connect(ui.save, SIGNAL(clicked()), this, SLOT(save_clicked(QString)));
}

void MyClass::save_clicked(QString userid)
{
    // process userid here    
}

比使用更好 signals/slots 只需使用一个变量。这是 class 的目标。添加类似 :

private:

QString userId;

然后在你的构造函数中添加:

MyClass::MyClass(QString userid, QString lastname, QString firstname, QWidget *parent)
: QWidget(parent)
{
    ui.setupUi(this);
    this.userId=userid;

}

像这样,您可以根据需要在 class 中使用 userId。

编辑:

添加你的 .h

private slots:
    void on_saveButton_clicked();

并在您的 .cpp 中

void MyClass::on_saveButton_clicked()
{
    // you can use userId here
}

如果你使用Qt Creator,这些功能可以自动添加到UI设计界面

首先,已经有人建议userid不需要传递到一个slot。将其声明为 MyClass 的成员并在 MyClass::save_clicked() 中简单地使用它就可以了。

如果您仍然想知道如何处理需要将参数传递给信号未提供的槽的情况,有多种方法可以实现,它们取决于您使用的 Qt 版本.

一般来说,Qt5 docs 中的以下内容适用于 Qt5 和 Qt4:

The signature of a signal must match the signature of the receiving slot. (In fact a slot may have a shorter signature than the signal it receives because it can ignore extra arguments.)

鉴于这一事实,您必须使用信号提供的内容(或不使用 - 取决于您是否需要它)或从其他地方获取数据。 slot 只是一个常规函数(在 Qt4 中受到更多限制,但在 Qt5 中,您基本上可以连接 任何可调用信号的东西 )并且在该函数中,您可以从您的设计允许的任何地方获取您需要的数据。成员变量方法很常见,但您也可以调用任何其他对象的另一个成员函数、自由函数或简单地在槽内计算您需要的任何内容。

注意:处理信号并不一定意味着您需要 任何 数据 - 这很常见,是的,但您也可以做一些简单的事情,例如调出 QMessageBox 用一些硬编码的文本或简单地清除一些文本编辑(想想像按钮做的事情 Clear Console)或执行一些外部进程或你有什么。

如果您需要插槽在调用时实际接收 数据,您有多种选择:

  • 使用信号提供的所有内容或部分内容
  • 使用 QSignalMapper 建立映射,对您的插槽参数进行有限控制
  • 恕我直言,使用存储所需内容的函数对象的高级方法,即您直接提供的仿函数或作为 lambda 或从 std::bind
  • 返回的函数对象

要使后者正常工作,您需要 C++11支持,但到目前为止,这应该不是问题。

在你上面的例子中,你可以用最基本的方法做这样的事情(未测试 - 请报告编译错误以便我修复答案):

MyClass::MyClass(QString userid, QString lastname, QString firstname, QWidget *parent)
: QWidget(parent)
{
  ...

  connect (
    ui.save, 
    &QPushButton::clicked, 
    std::bind (&MyClass::save_clicked, this, userid)
  );

  ...
}

在上述情况下,当 clicked()ui.save 发出时,std::bind 返回的函数调用包装器将被调用,后者将调用 MyClass::save_clickedMyClassthis 实例上并将 userid 传递给 save_clicked()

以上基本上就是你最初想要达到的效果。然而,这只是冰山一角。您可以更进一步,例如,绑定 anything 您想要的。

例如,假设您连接到按钮 toggled(bool checked) 提供的另一个信号。如果你想接收检查状态作为 bool 你自己提供的一些参数,例如 userid,你可以将上面的调用扩展到 std::bind 使用适当的占位符:

connect (
  ui.save, 
  &QPushButton::toggled, 
  std::bind (&MyClass::save_clicked, this, _1, userid /*, ... more args here*/)
);

您现在将拥有 save_clicked() 的以下签名:

save_clicked(bool, QString);

ui.save 发出 toggled(bool) 时,std::bind 返回的函数调用包装器将调用 MyClass::save_clicked,同时用 bool 代替 _1 您提供的 QString 作为 std::bind.

的第 4 个参数