在Qt信号和插槽中使用lambda语法并访问传递的参数

时间:2019-04-17 09:08:03

标签: c++ qt c++11 lambda signals-slots

我有一个带有此签名信号的类:

// CLASS A
signals:
    void requestToChangeRange(voltage_range_e vr, current_range_e cr, uint16_t bits);

还有另一个类具有这样的插槽(请注意额外的参数)

// CLASS C
public slots:
    void handleRequestRangeChange(voltage_range_e vr, current_range_e cr, uint16_t bits, uint16_t limiter);

然后我有一个班级“ B”,它是所有其他班级的集合点。当类“ A”发出信号时,类“ C”应将其重定向到类“ B”。但是,在类“ B”的插槽上的那个额外的参数是问题所在,因为那个额外的参数来自另一个类“ X”。

因此,如果“ A”和“ C”类的信号和插槽匹配,我将在“ B”类中执行以下操作:

// somewhere in CLASS B (the manager of all other classes)
connect(pClassA, &ClassA::requestToChangeRange,
    pClassC, &ClassC::handleRequestRangeChange);

但是显然,由于函数签名,这不起作用。我想做的是这样的:

// somewhere in CLASS B (the manager of all other classes)
connect(pClassA, &ClassA::requestToChangeRange,
this /* class B */, []() {
    // Get that last required parameter from class X
    uint16_t limiter = pClassX->getValue();
    // Call slot of class C
    pClassC->handleRequestRangeChange(vr, cr, bits, limiter);
});

那么我如何在lambda中访问那些传递的参数?这有可能吗?

2 个答案:

答案 0 :(得分:5)

您的lambda应该知道两个对象:[pClassX, pClassC],并接受信号的原始参数:(voltage_range_e vr, current_range_e cr, uint16_t bits)

所以您的连接应该这样开始:

connect(pClassA, &ClassA::requestToChangeRange, this,
    [pClassX, pClassC](voltage_range_e vr, current_range_e cr, uint16_t bits) {
    //...
});

关于connect()语句中的“接收器”:

连接到lambda时实际上并不需要指向QObject的指针,但它的目的是在发送方或接收方被破坏时,将删除信号插槽连接。

使用this意味着您必须确保删除pClassXpClassC中的任何一个后不再发出信号。或者,您可以使用pClassC作为接收者,然后必须确保pClassX保持有效,只要pClassCpClassA仍然存在...理想情况下,您应该指定pClassXpClassC作为接收者,但这是不可能的。为此,您可以利用QPointer的防护功能。

答案 1 :(得分:1)

在这种情况下值得一提的一个技巧是,如果您掌握了指向QObjects的指针,我建议您首先创建QPointer变量,然后在lambda中掌握THOSE。这样,您可以检查它们是否已删除。如果使用正常的信号和插槽,则可以解决此问题,但是使用lambda时,您可能需要自己处理参考的生命周期。

希望我们很快会获得更多方便的C ++捕获构造对象的方法。