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

Using lambda syntax in Qt signal and slot and accessing passed arguments

本文关键字:访问 语法 参数 lambda 信号 Qt 插槽      更新时间:2023-10-16

我有一个类,它有一个带有这个签名的信号:

// 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 中传递的参数呢?这可能吗?

您的 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意味着您必须确保在删除pClassX中的任何一个后,pClassC不再发出信号。或者,您可以使用pClassC作为接收器,然后您必须确保只要pClassCpClassA还活着,pClassX就保持有效......理想情况下,您将pClassXpClassC指定为接收器,但这是不可能的。您可以为此利用QPointer的保护功能。

在这种情况下值得一提的一个技巧是,如果你抓取指向 QObjects 的指针,我建议首先创建 QPointer 变量,并在 lambda 中抓取 THEM。这样,您可以检查它们是否已被删除。如果您使用普通信号和插槽,则可以处理此问题,但是对于lambda,您可能需要自己处理引用的终身时间。

希望我们很快就会得到更方便C++使用构造对象进行捕获的方法。