概念
信号是发生事件(如属性更改、动画状态变化、图片下载完成等)的对象发射的通知。
特定的信号发射后,可以通过相应的信号处理器获得通知。信号处理器的声明语法为:
on<Signal>
其中<Signal>
是信号的名字,首字母需要大写。
信号处理器必须在发射信号的对象的定义中进行声明,其中包含调用时要执行的JavaScript代码块。
例如,QtQuick模块中的MouseArea
类型就有一个clicked
信号。对应的信号处理器为onClciked
。
import QtQuick
Rectangle{
id: rect
width: 400; height:300
MouseArea{
anchors.fill: parent
onClicked:{
rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);
}
}
}
1. 声明信号
信号可以在C++中使用Q_SIGNAL
宏声明,也可以在QML文档中直接声明。
语法:
signal <signalName>[([<parameterName> : <parameterType>[,...]])]
同一作用域不能有两个同名的信号或方法。但是新的信号可以重用已有信号的名字,这意味着原来的信号会被新的信号隐藏,变得不可访问。
声明信号的例子:
import QtQuick
Item{
signal clicked
signal hovered()
signal actionPerformed(action: string, actionResult: var)
}
没有参数可以省略小括号。有参数必须声明。
还可以用另一种语法来声明:
signal actionCanceled(string action)
2. 属性改变信号
除了自定义的信号,QML类型还提供了一种内建的属性值改变信号。
声明一个自定义的属性,则会隐式地为该属性创建一个值改变信号以及一个相应的信号处理器on<PropertyName>Changed
。其中<PropertyName>
是自定义属性的名字,首字母大写。
3. 信号处理器
信号处理器是一类特殊的方法特性。
当对应的信号发射时,信号处理器会被QML引擎自动调用。
例子:
//SquareButton.qml
Rectangle {
id: root
property int side: 100
signal activated(real xPosition, real yPosition)
signal deactivated()
width: side
height: side
color: "red"
MouseArea {
anchors.fill: parent
onReleased: root.deactivated()
onPressed: (mouse) => {
return root.activated(mouse.x, mouse.y);
}
}
}
这些信号可以被SquareButton.qml
和同目录的其他QML文件接收,例如:
//main.qml
import QtQuick
Rectangle {
width: 400
height: 300
SquareButton {
anchors.fill: parent
onDeactivated: console.log("Deactivated")
onActivated: (xPosition, yPosition) => {
return console.log("Activated at " + xPosition + "," + yPosition);
}
}
}
在信号处理器中可以通过分配一个函数来访问信号中的参数。可以用例子中的箭头函数,也可以用匿名函数。例如:
onActivated: function(xpos, ypos) {console.log(xPos + "," + yPos)}
其中信号处理器的形参名称不必与信号的参数名称匹配。
可以值处理前面的参数,而略掉其后的参数,例如:
onActivated: (xPos) => console.log("xPosition:" + xPos)
4. Connections类型
除了上面的最基本用法,有时可能需要在发射信号的对象外部使用这个信号。
Qt Quick模块提供了Connections
类型,用于连接外部对象的信号。Connections
对象可以接收制定目标(target)的任意信号。
例如,下面的代码通过Connections
对象,在MouseArea
外部处理了MouseArea
发出的clicked
信号:
Rectangle {
id: rect
width: 400
height: 300
MouseArea {
id: mouseArea
anchors.fill: parent
}
Connections {
function onClicked() {
rect.color = "red";
}
target: mouseArea
}
}
这段代码中,Connections
的target
属性是mouseArea
,因而这个Connections
对象可以接收来自mouseArea
的任意信号。这里只关心clicked
信号,所有只添加了onClicked
信号处理器。
通常,使用信号处理器已经能够满足大多数应用。
但是,有时需要把一个信号与一个或多个方法或信号关联起来,这种语法就无能为力了。
QML的信号对象提供了connect()
函数,支持将一个信号与一个方法或者另外的信号连接起来,这与Qt/C++类似。
例子,将messageReceived
信号与3个方法连接:
import QtQuick
Rectangle {
id: relay
signal messageReceived(string person, string notice)
function sendToPost(person: string, notice: string) {
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);
}
Component.onCompleted: {
relay.messageReceived.connect(sendToPost);
relay.messageReceived.connect(sendeToTelegraph);
relay.messageReceived.connect(sendToEmail);
relay.messageReceived("Tom", "Happy Birthday");
}
}
即便这种需求很少,但是也会存在。
更常见的需求是将虚拟号与动态创建的对象关联起来,此时就不得不使用connect()
函数进行连接。
如果需要接触连接,可以调用信号对象的disconnect()
函数。
不仅如此,使用connect()
函数还可以构成一个信号链。
例如:
import QtQuick
Rectangle {
id: forwarder
signal send()
width: 400
height: 300
onSend: console.log("Send clicked")
Component.onCompleted: {
mouseArea.clicked.connect(send);
}
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: console.log("MouseArea clicked")
}
}
当MouseArea
发出clicked
信号时,自定义的send
信号也会被自动发射。