将信号连接到JavaScript中的内部处理程序



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元素,但只有在实际情况下才有意义

我认为这种混乱源于其他一些为您生成处理程序方法的语言/框架。onSignalfunction 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),因为信号不是直接连接到该函数,而是连接到调用它的匿名表达式。

相关内容

  • 没有找到相关文章

最新更新