StupidBeauty
Read times:4410Posted at:Tue May 21 11:25:44 2019 - no title specified

Qt 5.12文档翻译:Qt QML,信号及处理器事件系统,Signal and Handler Event System

应用程序和用户界面组件之间,需要互相通信。例如,作为一个按钮,需要知道自己被用户点击了。按钮可能会相应地改变自身的颜色以表明状态变化,或者做出某些逻辑操作。同时,应用程序也需要知道用户是否点击了按钮。应用程序可能还需要将这种点击事件传递给其它的应用程序。

QML中拥有一套信号和处理器机制,其中, 信号 ,即是代表事件,而信号是由 信号处理器 来响应的。每当某个信号被发射时,对应的信号处理器就会被调用。在处理器中放置一些逻辑,例如一段脚本或者其它操作,就能够让该组件对该事件做出响应。

使用信号处理器来接收信号

要想在特定对象的特定信号被发射时得到通知,就应当在该对象的定义中声明一个信号处理器,其名字为 on<Signal> ,其中, <Signal> 即是信号的名字,将首字母大写。在信号处理器中,包括的是,该处理器被调用时要执行的JavaScript代码。

例如, Qt Quick Controls 模块 中的 Button 类型,拥有一个 clicked 被点击 )信号,每当 该按钮被点击时,就会发射这个信号。 在这种情况下,用于接收这个信号的信号处理器就应当 onClicked 在以下的示例中,每当按钮被点击时, 就会调用 onClicked 处理器,使得其亲代 Rectangle (矩形)变成一种随机的颜色:

import QtQuick 2.12

import QtQuick . Controls 2.12

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> 是该属性的名字,将首字母大写。

例如, MouseArea 这个类型,拥有一个 pressed 属性。 要想在这个属性发生变动时得到通知,就需要写一个名为 onPressedChanged 的信号处理器:

import QtQuick 2.12

Rectangle {

id: rect

width: 100 ; height: 100

TapHandler {

onPressedChanged: console.log( "taphandler pressed?" , pressed)

}

}

尽管 TapHandler 的文档中并没有声称自己拥有一个名为 onPressedChanged 的信号处理 ,但是 ,由于事实 上存在着一个名为 pressed 的属性,所以,对应 的信号被隐式地提供了。

使用Connections 类型

某些情况 下,可能需要在发射某个信号的对象之外访问到该信号。 为了满足这种需求, QtQuick 模块中提供了 Connections 类型,用于连接 到任意对象的信号。 Connections 对象 ,可接收指定的 target (目标对象)的任意信号。

例如,前面示例 中的 onClicked 处理器, 可以改为由根元素 Rectangle 来接收并处理,具体做法就是,将 onClicked 处理器放置到一个其 target (目标对象)被设置为那个 button (按钮)对象的 Connections 对象中去:

import QtQuick 2.12

import QtQuick . Controls 2.12

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.12

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 已完成 )信号。实际 上,某个 completed 已完成 )信号的具有 Component 这种 附加类型 的对象, 由QML 引擎自动 附加 Rectangle 对象上去。 当此处的Rectangle 对象被创建时,引擎就会发射这个信号,于是触发了 Component.onCompleted 这个信号处理器。

附加 的信号处理器,使得各个对象能够在特定的对于单个对象很有意义的信号发生时,被通知 。例如,假设 ,不存在 Component.onCompleted 这个附加的信号处理器,那么, 一个对象就必须注册到特定对象的特定信号,才能收到这个通知。 这种 附加 的信号处理器 机制,使得各个对象能够在不添加额外代码的情况下,接收到特定的信号。

参考 附加 的属性及附加的信号处理器 ,以了解更多关于附加的信号处理器的信息。

向自定义QML 类型中加入信号

可使用 signal 关键字来向自定义的QML 类型中加入信号。

定义一个新信号的语法是:

signal <name>[([<type> <parameter name>[, ...]])]

对于信号的发射方式是,将该信号当成一个方法来调用。

例如, 以下代码位于一个 SquareButton.qml 文件中。 根元素 Rectangle 对象,拥有一个 activated 信号,这个信号会在子代 TapHandler 元素被点击时发射。 在这个特定示例中,发射activated 信号时,还会带上鼠标点击时的x 和y 坐标:

// SquareButton.qml

import QtQuick 2.12

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 信号处理器来连接到 activated 信号:

// myapplication.qml

SquareButton {

onActivated: console.log( "Activated at " + xPosition + "," + yPosition)

}

参考 信号属性 ,以了解更多关于向自定义QML 类型加入信号的信息。

将信号连接到方法和信号

信号对象 ,拥有一个 connect() 方法,可将信号连接到某个方法或另一个信号。如果某个信号 被连接到某个方法,那么,该信号被发射时,会自动调用对应的方法。 这种机制,使得,能够 使用 某个方法来接收信号,而不是使用信号处理器。

以下示例中, messageReceived 信号,被通过 connect() 方法连接到了三个方法:

import QtQuick 2.12

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.12

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 信号也会自动被发射。

输出内容

MouseArea clicked

Send clicked

Your opinions

Your name:Email:Website url:Opinion content:
- no title specified

HxLauncher: Launch Android applications by voice commands