程序和界面组件需要相互通信。QML 具有 signal、handler 机制,其中 signal 是事件,handler 响应信号。当发出 signal 时,会调用相应的 handler。
4.1 处理信号的 Handler
格式为 on<Signal>
,其中 <Signal>
是信号名,首字母大写。例如:
import QtQuick
import QtQuick.Controls
Rectangle {
id: rect
width: 250; height: 250
Button {
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
text: "Change color!"
onClicked: {
rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);
}
}
}
4.1.1 处理属性变化的 Handler
格式为 on<Property>Changed
,其中
import QtQuick
Rectangle {
id: rect
width: 100; height: 100
TapHandler {
onPressedChanged: console.log("taphandler pressed?", pressed)
}
}
4.1.2 Signal 参数
信号可以有参数,箭头函数和匿名函数都可以访问这些参数。例如,Status 组件有个 errorOccurred 信号(有关如何将信号添加到 QML 组件的更多信息,请参阅 Adding signals to custom QML types):
// Status.qml
import QtQuick
Item {
id: myitem
signal errorOccurred(message: string, line: int, column: int)
}
Status {
onErrorOccurred: (mgs, line, col) => console.log(`${line}:${col}: ${msg}`)
}
注意:函数中的形参名不必与信号中的参数名相同。
如果不需要处理所有参数,则可以省略尾随参数:
Status {
onErrorOccurred: function (message) { console.log(message) }
}
您可以使用一些占位符名称来向读者表明它们并不重要:
Status {
onErrorOccurred: (_, _, col) => console.log(`Error happened at column ${col}`)
}
注意:代替使用函数,可以使用纯代码块,但不鼓励使用。在这种情况下,所有信号参数都被注入到块的作用域中。但是,这会使代码难以阅读,因为不清楚参数的来源,并导致 QML 引擎中的查找速度变慢。不推荐以这种方式注入参数,如果实际使用该参数会导致运行时警告。
4.1.3 使用 Connection 类型
QtQuick 模块提供了 Connections 类型。一个 Connections 对象可以接收 target 指定的对象的信号。例如:
import QtQuick
import QtQuick.Controls
Rectangle {
id: rect
width: 250; height: 250
Button {
id: button
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
text: "Change color!"
}
Connections {
target: button
function onClicked() {
rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);
}
}
}
4.1.4 附加的 signal handler
一个 attached signal handler 从一个 attaching type 而不是在其中声明处理程序的对象接收信号。例如,Component.onCompleted 是一个附加的 signal handler,通常用于在其创建过程完成时执行一些 JavaScript 代码:
import QtQuick
Rectangle {
width: 200; height: 200
color: Qt.rgba(Qt.random(), Qt.random(), Qt.random(), 1)
Component.onCompleted: {
console.log("The rectangle's color is", color)
}
}
onCompleted
未响应来自 Rectangle 类型的 completed
信号。相反,QML 引擎已自动将具有 completed
信号的 Component 附加类型的对象附加到 Rectangle 对象。创建 Rectangle 对象时,引擎会发出此信号,从而触发 Component.onCompleted。
附加的 signal handler 允许向对象通知对每个单独对象重要的特定信号。例如,如果没有 Component.onCompleted,则对象无法在不注册来自某个特殊对象的某些特殊信号的情况下接收此通知。附加的 signal handler 机制使对象无需额外代码即可接收特定信号。
更多信息,请参阅 Attached properties and attached signal handlers。
4.2 向自定义 QML 类型添加信号
使用 signal 关键字,定义新信号的语法是:
//语法
signal <name>[([<type> <parameter name>[, ...]])]
//示例
// SquareButton.qml
import QtQuick
Rectangle {
id: root
signal activated(real xPosition, real yPosition) //定义activated信号
property point mouseXY
property int side: 100
width: side; height: side
TapHandler {
id: handler
onTapped: root.activated(root.mouseXY.x, root.mouseXY.y) //鼠标点击发出activated信号
onPressedChanged: root.mouseXY = handler.point.position
}
}
//现在SquareButton的任何对象都可以使用onActivated连接到激活的信号:
// myapplication.qml
SquareButton {
onActivated: (xPosition, yPosition)=> console.log("Activated at " + xPosition + "," + yPosition)
}
有关为自定义 QML 类型编写信号的更多详细信息,请参阅 Signal Attributes。
4.3 建立 signal-method、signal-signal 间的连接
Signal 对象有一个 connect() 来将信号连接到一个方法或另一个信号。这种机制使信号能够由方法而不是 signal handler 接收。大多数使用 signal handler 就足够了,而使用 connect 方法允许多个方法接收信号。此外,connect 方法在将信号连接到动态创建的对象时很有用。例如,使用 connect()
方法将 messageReceived
信号连接到三个方法:
import QtQuick
Rectangle {
id: relay
signal messageReceived(string person, string notice)
Component.onCompleted: {
relay.messageReceived.connect(sendToPost)
relay.messageReceived.connect(sendToTelegraph)
relay.messageReceived.connect(sendToEmail)
relay.messageReceived("Tom", "Happy Birthday")
}
function sendToPost(person, notice) {
console.log("Sending to post: " + person + ", " + notice)
}
function sendToTelegraph(person, notice) {
console.log("Sending to telegraph: " + person + ", " + notice)
}
function sendToEmail(person, notice) {
console.log("Sending to email: " + person + ", " + notice)
}
}
Signal 对象还有一个 disconnect() 用于删除连接的信号:
Rectangle {
id: relay
//...
function removeTelegraphSignal() {
relay.messageReceived.disconnect(sendToTelegraph)
}
}
4.3.1 Signal-Signal
示例:
import QtQuick
Rectangle {
id: forwarder
width: 100; height: 100
signal send()
onSend: console.log("Send clicked")
TapHandler {
id: mousearea
anchors.fill: parent
onTapped: console.log("Mouse clicked")
}
Component.onCompleted: {
mousearea.tapped.connect(send) //TapHandler发射tapped信号后,自动发射send信号
}
}
输出: Mouse clicked Send clicked