QML- 信号和事件系统
- 一、概述
- 二、信号事件处理系统使用
- 1. 用信号处理器接收信号
- 2. 信号处理程序
- 3. 使用Connections 类型
- 4. 附加信号处理程序
- 三、向自定义QML类型添加信号
- 四、将信号连接到方法和信号
- 1. 信号与信号的连接
一、概述
应用程序和用户界面组件需要相互通信。例如,一个按钮需要知道用户是否点击了它。按钮可以改变颜色来表示其状态或执行某些逻辑。同样,应用程序需要知道用户是否点击了按钮。应用程序可能需要将此单击事件转发给其他应用程序。
QML具有信号和处理程序机制,其中信号是事件,信号通过信号处理程序进行响应。在发出信号时,调用对应的信号处理程序。在处理程序中放置诸如脚本或其他操作之类的逻辑可以让组件响应事件。
二、信号事件处理系统使用
1. 用信号处理器接收信号
为了在为特定对象发出特定信号时接收通知,对象定义应该声明一个名为 < signal > 的信号处理程序,其中 < signal > 是信号的名称,首字母大写。信号处理程序应该包含调用信号处理程序时要执行的 JavaScript 代码。
例如,Qt Quick Controls模块中的Button类型有一个clicked信号,当用户单击按钮时就会触发这个信号。
查阅参考资料知道 Button 继承了 AbstractButton 的信号功能。
在这种情况下,用于接收该信号的信号处理程序应该是onClicked。Qt 是是默认设置了 信号处理函数就是 on+信号名(信号首字母大写)
比如被按下的时候,处理函数就是 :onPressed()
在下面的示例中,每当单击按钮时,都会调用onClicked处理程序,并为父矩形应用随机颜色:
import QtQuick 2.14
import QtQuick.Controls 2.14
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);
}
}
}
2. 信号处理程序
当QML属性的值发生变化时,会自动发出一个信号。这种类型的信号是属性变化信号,这些信号的信号处理程序以 < property >Changed的形式编写,其中< property >是属性的名称,第一个字母大写。
例如,MouseArea类型有一个pressed属性。为了在这个属性改变时收到通知,写一个名为onPressedChanged的信号处理程序:
import QtQuick 2.14
Rectangle {
id: rect
width: 100; height: 100
TapHandler {
onPressedChanged: console.log("taphandler pressed?", pressed)
}
}
即使TapHandler文档没有记录名为onPressedChanged的信号处理程序,但该信号是由pressed属性存在这一事实隐式提供的。
3. 使用Connections 类型
在某些情况下,可能需要访问发出信号的对象之外的信号。为此,QtQuick模块提供了连接到任意对象信号的连接类型。连接对象可以从它指定的目标接收任何信号。 这个类型相当于就是一个 独立功能的 信号连接处理器。
例如,前面例子中的onClicked处理程序可以由根矩形接收,方法是将onClicked处理程序放在目标设置为按钮的Connections对象中:
import QtQuick 2.14
import QtQuick.Controls 2.14
Rectangle {
id: rect
width: 250; height: 250
Button {
id: button
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
text: "Change color!"
}
Connections {
target: button
onClicked: {
rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);
}
}
}
4. 附加信号处理程序
附加的信号处理程序接收来自附加类型的信号,而不是声明该处理程序的对象。
例如Component。onCompleted是一个附加的信号处理程序。它通常用于在创建过程完成后执行一些JavaScript代码。下面是一个例子:
import QtQuick 2.14
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引擎自动附加到 Rectangle 对象。当创建 Rectangle 对象时,引擎会发出这个信号,从而触发 Component.onCompleted 信号处理程序。
附加的信号处理程序允许每个对象以特定信号通知待响应对象做出响应,例如,一个对象如果没有从某些特殊对象注册某些特殊信号,就无法接收此通知。附加的信号处理程序机制使对象能够接收特定的信号,而无需额外的代码。
三、向自定义QML类型添加信号
信号可以通过signal关键字添加到自定义QML类型中。这个一般就是我们自己用封装控件的时候用到的
定义新信号的语法是:
signal <name>[([<type> <parameter name>[, ...]])]
通过将信号作为方法调用来发出信号。
例如,下面的代码定义在名为SquareButton.qml的文件中。根矩形对象有一个激活的信号,每当子TapHandler被点击时就会发出这个信号。在这个例子中,激活的信号是通过鼠标点击的x和y坐标发出的:
// SquareButton.qml
import QtQuick 2.14
Rectangle {
id: root
signal activated(real xPosition, real yPosition)
property point mouseXY
property int side: 100
width: side; height: side
TapHandler {
id: handler
onTapped: root.activated(mouseXY.x, mouseXY.y)
onPressedChanged: mouseXY = handler.point.position
}
}
现在SquareButton的任何对象都可以通过onActivated信号处理程序连接到激活的信号:
// myapplication.qml
SquareButton {
onActivated: console.log("Activated at " + xPosition + "," + yPosition)
}
有关为自定义QML类型编写信号的更多细节,请参见信号属性。
四、将信号连接到方法和信号
Signal对象有一个connect()方法,用于将一个信号连接到一个方法或另一个信号。当一个信号连接到一个方法时,只要这个信号发出,这个方法就会自动被调用。该机制使信号可以由方法接收,而不是由信号处理程序接收。 也是自己封装控件的时候调用时用到的。
下面,messagerreceived 信号使用 connect() 方法连接到三个方法:
import QtQuick 2.14
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)
}
}
在很多情况下,通过信号处理程序而不是connect()函数接收信号就足够了。但使用connect方法时,信号可以由多个方法接收,如前所述,这对于信号处理程序来说是不可能的,因为它们必须唯一命名。此外,在将信号连接到动态创建的对象时,connect方法很有用。就是批量的创建列表对每一个列表元素都要绑定的时候。
有一个对应的disconnect()方法可以移除连接的信号:
Rectangle {
id: relay
//...
function removeTelegraphSignal() {
relay.messageReceived.disconnect(sendToTelegraph)
}
}
1. 信号与信号的连接
通过连接信号和其他信号,connect()方法可以形成不同的信号链。
import QtQuick 2.14
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的tap信号时,send信号也会自动触发。
output:
MouseArea clicked
Send clicked