以MenuItem
为例,通常在QML中,为triggered
信号指定处理程序很简单:
MenuItem {
onTriggered: {
console.log("Hey");
}
}
现在,如果我想做同样的事情,但改为动态创建的MenuItem
,例如通过Menu.addItem()
,那么连接和指定信号处理程序的语法是什么?
我没想到这会奏效,但这里有一个可行的解决方案:
function onTriggered() {
console.log("Hey");
}
var newItem = myMenu.addItem("Item 1");
newItem.triggered.connect(onTriggered);
然而,还有更好的方法吗?上面我定义了一个自定义函数,恰好命名为onTriggered
,但它可以命名为任何名称,对吧?所以这段代码没有使用内置的处理程序,这就是为什么我想知道是否有一个更整洁的解决方案?
更重要的是,后来我注意到了这种方法的进一步问题:在for循环中,如果处理程序使用了一个临时变量,那么事情就不起作用了:
for (var i = 0; i < myArray.length; i ++) {
var info = myArray[i];
var newItem = myMenu.addItem("Item " + i);
newItem.triggered.connect(function() {
console.log(info);
});
}
在这里,您将看到控制台在触发时为所有添加的菜单项打印myArray
中的最后一个info
。如何为每个单独的菜单项正确设置独立的处理程序?
除了注释,您还可以轻松地让它变得"更容易":
Menu {
id: myMenu
function add(text, handler) {
var newItem = addItem(text)
newItem.triggered.connect(handler)
}
}
就这样,问题解决了,现在你可以简单地myMeny.add("Item 1", onTriggered)
至于你在循环和函子中得到的结果,那是因为JS的作用域规则。查看链接的答案,了解如何解决此问题的详细信息。
所以这段代码没有使用内置的处理程序
不要把onSignal
看作一个处理程序,它只是一个附加处理程序的钩子。可以将其视为声明性连接语法。当然,您也可以在declarative中使用Connection
元素,但只有在实际情况下才有意义
我认为这种混乱源于其他一些为您生成处理程序方法的语言/框架。onSignal
与function onSignal() { expression }
不同——后者是一个处理程序函数,前者是处理程序钩子,它只是将信号连接到绑定的expression.eval()
。Qt文档也将onSignal
称为处理程序,IMO在技术和概念上都是错误的,因为处理程序是执行的代码,所以处理程序是绑定到onSignal
的任何程序。
所以你可以放心,你担心的代码不会导致任何冗余或低效,也不会留下任何未使用的东西,事实上这是QML中正确的做法。
话虽如此,可以拥有"内置处理程序",但这是一件非常不同的事情:
// SomeItem.qml
Item {
signal someSignal
onSomeSignal: console.log("I am a built in handler")
}
// main.qml
SomeItem {
onSomeSignal: console.log("I am another handler")
Component.onCompleted: {
someSignal.connect(function(){console.log("Yet another handler")})
someSignal()
}
}
控制台中的输出将显示:
qml: I am a built in handler
qml: I am another handler
qml: Yet another handler
正如您所看到的,它实际上不是一个处理程序,而是一个连接钩子。没有阴影,没有"替换/不使用内置处理程序",只有一个信号与三个表达式的求值有3个连接。
将signal.connect()
与命名函数一起使用确实有一个优点,如果以后需要删除内置处理程序或其他处理程序,则可以使用signal.disconnect(namedFunction)
。如果您使用onSignal: expr
,我不确定您是否可以做到这一点,因为您没有引用匿名表达式的方法。请注意,如果您使用onSignal: namedFunction()
,这将不起作用,您将无法使用signal.disconnect(namedFunction)
,因为信号不是直接连接到该函数,而是连接到调用它的匿名表达式。