Использование лямбда-синтаксиса в сигнале и слоте Qt и доступ к переданным аргументам - PullRequest
4 голосов
/ 17 апреля 2019

У меня есть класс, у которого есть сигнал с этой подписью:

// 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);
});

Так как я могу получить доступ к этим переданным параметрам внутри лямбды? Это вообще возможно?

Ответы [ 2 ]

5 голосов
/ 17 апреля 2019

Ваша лямбда должна знать оба объекта: [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 ():

Этот указатель на QObject на самом деле не нужен при подключении к лямбде, но он служит той цели, что соединение сигнал-слот будет удалено, если отправитель или получатель будут уничтожены.

Использование this означает, что вы должны убедиться, что после удаления любого из pClassX, pClassC вы больше не излучаете сигнал. В качестве альтернативы вы можете использовать pClassC в качестве получателя, тогда вы должны быть уверены, что pClassX остается в силе до тех пор, пока pClassC и pClassA живы ... В идеале вы бы указали pClassX AND pClassC как приемники, но это невозможно. Для этого вы можете использовать защитную функцию QPointer.

1 голос
/ 24 апреля 2019

В этом контексте стоит упомянуть одну хитрость: если вы захватываете указатели на объекты QObject, я бы порекомендовал сначала создать переменные QPointer и использовать THOSE в лямбда-выражении.Таким образом, вы можете проверить, были ли они удалены.Если вы используете нормальный сигнал и слоты, об этом позаботятся, но с лямбдами вам, возможно, придется самостоятельно обрабатывать ссылки в течение всей жизни.

Надеемся, что вскоре мы получим более удобные способы захвата C ++ с помощью созданных объектов.

...