我认为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问题?
答案 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