将信号连接到 JavaScript 中的内部处理程序
Connect signal to intrinsic handler in JavaScript
以MenuItem
为例,通常在QML中,为triggered
信号指定handler很简单:
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);
});
}
在这里您会看到控制台在触发时为所有添加的菜单项打印 last info
in myArray
。如何为每个单独的菜单项正确设置独立的处理程序?
除了评论,还可以轻松搞定"easier":
Menu {
id: myMenu
function add(text, handler) {
var newItem = addItem(text)
newItem.triggered.connect(handler)
}
}
到此为止,问题已解决,现在您只需 myMeny.add("Item 1", onTriggered)
至于你在循环和仿函数中得到的结果,那是因为JS的作用域规则。查看链接的答案以了解如何解决该问题的详细信息。
So this code piece doesn't make use of the built-in handler
不要把onSignal
当成一个处理程序,它只是一个挂接处理程序的钩子。将其视为声明性连接语法。当然,您也可以在声明中使用 Connection
元素,但只有在实际情况需要时才有意义。
我认为这种混淆源于其他一些确实为您生成处理程序方法的语言/框架。 onSignal
不同于 function onSignal() { expression }
- 后者是处理函数,前者是处理程序挂钩,它只是将信号连接到绑定 expression.eval()
。 Qt 文档也将 onSignal
称为处理程序,IMO 在技术上和概念上都是错误的,因为处理程序是要执行的代码,处理程序是您绑定到 onSignal
.[=27= 的任何内容]
所以您可以高枕无忧,您担心的代码不会导致任何形式的冗余或低效,也不会留下任何未使用的东西,实际上是在 QML 中做事的正确方法。
综上所述,您可以 "built in handlers",但这是完全不同的事情:
// 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
如您所见,它实际上不是一个处理程序,而是一个连接挂钩。没有阴影,没有 "replacing / not using the built in handler",只有一个带有 3 个连接的信号来评估三个表达式。
将 signal.connect()
与命名函数一起使用确实有一个优势,如果您需要删除内置或其他处理程序,您可以稍后 signal.disconnect(namedFunction)
。我不确定如果您使用 onSignal: expr
是否可以这样做,因为您没有办法引用该匿名表达式。请注意,如果您使用 onSignal: namedFunction()
这将不起作用,您将无法 signal.disconnect(namedFunction)
因为信号没有直接连接到该函数,而是连接到调用它的匿名表达式。
以MenuItem
为例,通常在QML中,为triggered
信号指定handler很简单:
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);
});
}
在这里您会看到控制台在触发时为所有添加的菜单项打印 last info
in myArray
。如何为每个单独的菜单项正确设置独立的处理程序?
除了评论,还可以轻松搞定"easier":
Menu {
id: myMenu
function add(text, handler) {
var newItem = addItem(text)
newItem.triggered.connect(handler)
}
}
到此为止,问题已解决,现在您只需 myMeny.add("Item 1", onTriggered)
至于你在循环和仿函数中得到的结果,那是因为JS的作用域规则。查看链接的答案以了解如何解决该问题的详细信息。
So this code piece doesn't make use of the built-in handler
不要把onSignal
当成一个处理程序,它只是一个挂接处理程序的钩子。将其视为声明性连接语法。当然,您也可以在声明中使用 Connection
元素,但只有在实际情况需要时才有意义。
我认为这种混淆源于其他一些确实为您生成处理程序方法的语言/框架。 onSignal
不同于 function onSignal() { expression }
- 后者是处理函数,前者是处理程序挂钩,它只是将信号连接到绑定 expression.eval()
。 Qt 文档也将 onSignal
称为处理程序,IMO 在技术上和概念上都是错误的,因为处理程序是要执行的代码,处理程序是您绑定到 onSignal
.[=27= 的任何内容]
所以您可以高枕无忧,您担心的代码不会导致任何形式的冗余或低效,也不会留下任何未使用的东西,实际上是在 QML 中做事的正确方法。
综上所述,您可以 "built in handlers",但这是完全不同的事情:
// 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
如您所见,它实际上不是一个处理程序,而是一个连接挂钩。没有阴影,没有 "replacing / not using the built in handler",只有一个带有 3 个连接的信号来评估三个表达式。
将 signal.connect()
与命名函数一起使用确实有一个优势,如果您需要删除内置或其他处理程序,您可以稍后 signal.disconnect(namedFunction)
。我不确定如果您使用 onSignal: expr
是否可以这样做,因为您没有办法引用该匿名表达式。请注意,如果您使用 onSignal: namedFunction()
这将不起作用,您将无法 signal.disconnect(namedFunction)
因为信号没有直接连接到该函数,而是连接到调用它的匿名表达式。