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

时间:2015-11-15 03:31:44

标签: qt qml qt5 qtquick2

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);
    });
}

在这里,您会看到控制台在info中打印 last myArray,以便在触发时显示所有添加的菜单项。如何为每个菜单项正确设置独立处理程序?

1 个答案:

答案 0 :(得分:1)

除了评论之外,您还可以轻松地使其更容易&#34;:

Menu {
    id: myMenu

    function add(text, handler) {
        var newItem = addItem(text)
        newItem.triggered.connect(handler)
    }
}

你有它,问题解决了,现在你可以简单地myMeny.add("Item 1", onTriggered)

至于你在循环和仿函数中得到的结果,这是因为JS的范围规则。查看链接的答案,了解如何解决该问题的详细信息。

  

所以这段代码没有使用内置处理程序

不要将onSignal视为处理程序,它只是附加处理程序的钩子。将其视为声明性连接语法。当然,你也可以在声明中使用Connection元素,但只有当情况真正有用时它才有意义。

我认为这种混淆源于其他一些为您生成处理程序方法的语言/框架。 onSignalfunction onSignal() { expression }不同 - 后者是处理函数,前者是处理程序钩子,它只是将信号连接到绑定的expression.eval()。 Qt文档也将onSignal称为处理程序,IMO在技术上和概念上都是错误的,因为处理程序是执行的代码,处理程序是绑定到onSignal的任何内容。

所以你可以轻松休息,你担心的代码不会导致任何冗余或效率低下,并且不会留下任何未使用的东西,实际上是用QML做事的正确方法。

所有这一切,你可以拥有内置处理程序&#34;但它是一个非常不同的东西:

// 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

如你所见,它不是一个真正的处理程序,而是一个连接钩子。没有阴影,没有&#34;替换/不使用内置处理程序&#34;,只有一个信号有3个连接来评估三个表达式。

signal.connect()与命名函数一起使用确实有一个优点,如果您需要删除内置函数或其他处理程序,可以稍后signal.disconnect(namedFunction)。如果您使用onSignal: expr,我不确定您是否可以这样做,因为您没有办法引用该匿名表达式。请注意,如果您使用onSignal: namedFunction()这将无效,您将无法signal.disconnect(namedFunction),因为信号不直接连接到该函数,而是调用它的匿名表达式。