QT - 信号和事件处理系统
应用程序和用户界面组件需要相互通信。例如,一个按钮需要知道用户已单击它。该按钮可以更改颜色以指示其状态或执行某些逻辑。同样,应用程序需要知道用户是否正在单击按钮。应用程序可能需要将此点击事件中继到其他应用程序。
QML具有信号和信号处理机制,其中信号是事件,信号通过信号处理程序进行响应。发出信号时,将调用相应的信号处理程序。在处理程序中放置诸如脚本或其他操作之类的逻辑,使组件可以响应事件。
使用信号处理程序接收信号
为了在特定对象发出特定信号时接收通知,对象定义应声明一个名为on<Signal>的信号处理程序,其中<Signal>是信号的名称,首字母大写。信号处理程序应包含在调用信号处理程序时要执行的JavaScript代码。
例如,来自Qt Quick Controls模块的Button类型具有一个信号,该信号在单击按钮时发出。在这种情况下,用于接收此信号的信号处理程序应为onClicked
。在下面的示例中,每当单击按钮时,都会调用处理程序,并为父Rectangle应用随机颜色:
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
属性存在的事实隐式提供的。
使用连接(Connections)类型
在某些情况下,可能希望访问发出该信号的对象之外的信号。为此,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
处理程序没有响应于completed
从信号矩形类型。而是,带有信号的Component
附加类型的对象已由QML引擎completed
自动附加到Rectangle对象。创建Rectangle对象时,引擎会发出此信号,从而触发Component.onCompleted
信号处理程序。
附加的信号处理程序允许将对每个单独对象重要的特定信号通知给对象。Component.onCompleted
例如,如果没有附加的信号处理程序,则一个对象如果不从某个特殊对象注册某些特殊信号就无法接收该通知。所述附接的信号处理程序机制使得对象以接收特定的信号而无需额外的代码。
有关附加信号处理程序的更多信息,请参见附加属性和附加信号处理程序。
向自定义QML类型添加信号
可以通过signal
关键字将信号添加到自定义QML类型。
定义新信号的语法为:
signal <name>[([<type> <parameter name>[, ...]])]
通过调用信号作为一种方法来发出信号。
例如,以下代码在名为的文件中定义SquareButton.qml
。根矩形对象具有一个activated
信号,每当子被发射TapHandler是tapped
。在此特定示例中,激活的信号以鼠标单击的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()
方法可以形成不同的信号链。
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的tapped
信号时,该send
信号也会自动发射。
output:
MouseArea clicked
Send clicked