将信号连接到插槽,但只调用一次插槽然后自动断开它们

时间:2017-07-10 18:15:58

标签: qt qml qtquick2 observer-pattern signals-slots

考虑这个JS代码:

function handleSig() {
    emitter.someSig.disconnect(handleSig);
    // do some work here
}

emitter.someSig.connect(handleSig);

可以在没有显式断开连接和命名函数的情况下编写吗?

理想情况下,我喜欢这样的事情:

emitter.someSig.connect(
    function() {
        // do some work here
    },
    Qt.SingleShotConnection
);

近似重复:Automatically disconnect after first signal emission - 但这个问题是关于Python而我的是关于QML和C ++。

2 个答案:

答案 0 :(得分:5)

您可以创建一个小辅助函数,为您执行断开连接,如:

function connectOnce(sig, slot) {
    var f = function() {
        slot.apply(this, arguments)
        sig.disconnect(f)
    }
    sig.connect(f)
}

作为使用说明:

import QtQuick 2.7
import QtQuick.Controls 2.0

ApplicationWindow {
    id: myWindow
    visible: true
    width: 600
    height: 600
    color: 'white'

    signal action(string name)

    function slot(name) {
        console.log(name)
    }

    Button {
        text: 'connect'
        onClicked: {
            connectOnce(action, slot)
        }
    }

    Button {
        y: 80
        text: 'action'
        onClicked: {
            action('test')
        }
    }

    function connectOnce(sig, slot) {
        var f = function() {
            slot.apply(this, arguments)
            sig.disconnect(f)
        }
        sig.connect(f)
    }
}

上面两个按钮会在单次模式下将slotslot2连接到信号action。 按钮操作将触发信号action,它将执行插槽的次数与连接的次数相同。然后他们会立即断开连接。

您可以将函数connectOnce放入库中,以便随时随地使用它。

此解决方案很容易扩展为更通用的形式,通过在闭包中引入计数器来连接要执行的函数n次:

function connectN(sig, slot, n) {
    if (n <= 0) return
    var f = function() {
        slot.apply(this, arguments)
        n--
        if (n <= 0) sig.disconnect(f)
    }
    sig.connect(f)
}

答案 1 :(得分:3)

我在这里找到了一个C ++的答案,虽然它有点不优雅:

https://forum.qt.io/topic/67272/how-to-create-a-single-shot-one-time-connection-to-a-lambda/2

该链接的代码:

QMetaObject::Connection * const connection = new QMetaObject::Connection;
*connection = connect(_textFadeOutAnimation, &QPropertyAnimation::finished, [this, text, connection](){
    QObject::disconnect(*connection);
    delete connection;
});

我仍然坚持要求更好的C ++答案和QML答案。