应用程序和用户界面组件需要相互通信。例如,一个按钮需要知道用户已单击它。该按钮可以更改颜色以指示其状态或执行某些逻辑。同样,应用程序需要知道用户是否正在单击按钮。应用程序可能需要将此点击事件中继到其他应用程序。
QML具有信号和处理程序机制,其中信号是事件,信号通过信号处理程序进行响应。发出信号时,将调用相应的信号处理程序。在处理程序中放置诸如脚本或其他操作之类的逻辑,使组件可以响应事件。
使用信号处理程序接收信号
为了在特定对象发出特定信号时接收通知,对象定义应声明一个名为on <Signal>的信号处理程序,其中<Signal>是信号的名称,首字母大写。信号处理程序应包含在调用信号处理程序时要执行的JavaScript代码。
例如,来自Qt Quick Controls模块的Button类型具有一个信号,该信号在单击按钮时发出。在这种情况下,用于接收此信号的信号处理程序应为。在下面的示例中,每当单击按钮时,都会调用处理程序,并为父Rectangle应用随机颜色:clickedonClickedonClicked
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); } } }
属性更改信号处理程序
QML属性的值更改时,会自动发出信号。此类信号是属性更改信号,这些信号的信号处理程序以on <Property> Changed的形式编写,其中<Property>是属性的名称,首字母大写。
例如,鼠标区域类型具有一个pressed特性。要在此属性更改时接收通知,请编写名为的信号处理程序onPressedChanged:
import QtQuick 2.14 Rectangle { id: rect width: 100; height: 100 TapHandler { onPressedChanged: console.log("taphandler pressed?", pressed) } }
即使TapHandler文档中没有记录名为的信号处理程序onPressedChanged,该信号还是由该pressed属性存在的事实隐式提供的。
使用连接类型
在某些情况下,可能希望访问发出该信号的对象之外的信号。为此,QtQuick模块提供用于连接任意对象信号的Connections类型。连接对象可以接收来自它的指定的任何信号的目标。
例如,onClicked在前面的示例中的处理程序可能已被由所述根接收矩形代替,通过将onClicked处理程序连接到具有其对象目标集到button:
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); } } }
附加信号处理程序
一个附加的信号处理程序,从一个接收信号附加类型,而不是在其内的处理程序被声明的对象。
例如,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信号。而是,带有信号的Component 附加类型的对象已由QML引擎completed自动附加到Rectangle对象。创建Rectangle对象时,引擎会发出此信号,从而触发Component.onCompleted信号处理程序。
附加的信号处理程序允许将对每个单独对象重要的特定信号通知给对象。例如,Component.onCompleted如果没有附加的信号处理程序,则一个对象如果不从某个特殊对象注册某些特殊信号就无法接收该通知。所述附接的信号处理程序机制使得对象以接收特定的信号而无需额外的代码。
有关附加信号处理程序的更多信息,请参见附加属性和附加信号处理程序。
向自定义QML类型添加信号
可以通过signal关键字将信号添加到自定义QML类型。
定义新信号的语法为:
signal <name>[([<type> <parameter name>[, ...]])]
通过调用信号作为一种方法来发出信号。
例如,以下代码在名为的文件中定义SquareButton.qml。根Rectangle
对象具有一个activated信号,每当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可以activated使用onActivated信号处理程序连接到信号:
// myapplication.qml SquareButton { onActivated: console.log("Activated at " + xPosition + "," + yPosition) }
有关为自定义QML类型编写信号的更多详细信息,请参见信号属性。
将信号连接到方法和信号
信号对象具有connect()方法将信号连接到一个方法或另一个信号。当信号连接到方法时,只要发出信号,该方法就会自动调用。这种机制使信号可以通过方法而不是信号处理程序来接收。
下面,messageReceived使用该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) } }
信号对信号连接
通过将信号连接到其他信号,该connect()方法可以形成不同的信号链。
Rectangle { id: forwarder width: 100 height: 100 anchors.fill: parent signal send onSend: console.log("Send clicked") color: "grey" TapHandler { id: mousearea onTapped: console.log("Mouse clicked") } Component.onCompleted: { mousearea.tapped.connect(send) } }
每当发射TapHandler的tapped信号时,该send信号也会自动发射。
output:
MouseArea clicked
Send clicked