QML:Lambda函数意外工作

时间:2015-03-06 12:11:54

标签: javascript qt lambda qml

我认为QML支持lambda函数,因为JavaScript支持匿名函数,而且函数是一流的对象,但它们并没有按照我的预期工作。拿这个代码:

Item {
    property var items: []

    function handler( item ) {
        console.log( item );
    }

    Component.onCompleted: {
        for ( var i = 0; i < 3; ++i ) {
            var item = someObj.createObject();
            item.someValueChanged.connect( function() {
                handler( item ); } );

            items.push( item );
            console.log( "Adding:", item );
        }
    }

    Component {
        id: someObj

        Item {
            property bool someValue: false

            Timer {
                running: true
                onTriggered: {
                    parent.someValue = true;
                }
            }
        }
    }
}

我尝试使用lambda function() { handler( item ); },以便在发出someObj::someValueChanged信号时,将发出项目传递给handler( item )函数。

假设每个循环都会创建一个新的lambda实例,而item引用会带有在该循环中创建的someObj实例的引用(即item将被lambda捕获。但是,输出似乎并非如此:

qml: Adding: QQuickItem_QML_1(0x2442aa0)
qml: Adding: QQuickItem_QML_1(0x2443c00)
qml: Adding: QQuickItem_QML_1(0x2445370)
qml: QQuickItem_QML_1(0x2445370)
qml: QQuickItem_QML_1(0x2445370)
qml: QQuickItem_QML_1(0x2445370)

正如您所看到的,要么在每个循环上替换整个函数,要么只替换item引用,以便最终只引用最后创建的someObj。有人可以向我解释为什么lambdas(如果它甚至是什么)不按照我期望的方式工作吗?这是一个QML问题,还是一般的JavaScript问题?

2 个答案:

答案 0 :(得分:11)

尝试这样的事情:

item.someValueChanged.connect(function(capture) {
    return function() {
        handler(capture)}
}(item))

直观,对吧? :d

如果JS使用&#34;阻止范围&#34;对于每个循环迭代,将引用3个不同的item,并且它将按预期工作&#34;。但是&#34;功能范围&#34;只引用了一个item,它引用了它的最终值,因此需要使用该黑客来捕获&#34;每个时间价值。

只是为了解释它,如果它不是立即显而易见的,信号连接到一个处理程序,该处理程序由一个函数仲裁,该函数在特定时间捕获参数值作为离散对象,用于提供给处理程序。

希望早期的Qt 5.12版本能够通过引入对let,a.k.a块范围变量的支持来解决这个问题。

更新:我可以确认使用5.12,它现在按预期工作:

let item = someObj.createObject(); // will produce 3 distinct obj refs

答案 1 :(得分:0)

dtech's answer解决了这个问题(谢谢!)但我们可以简化它,以便更清楚地了解到底发生了什么。 “内部”功能需要是匿名的,但不需要“外部”功能。使用外部函数的常规函数​​使代码更容易理解,并且更容易自我记录,因为函数具有名称。外部函数创建一个信号处理程序,因此等效代码可以是:

flex-container