文章目录
一、开篇
QtQuick有一个信号处理机制,其中信号是事件,信号处理程序能够响应信号。当发出信号时,QtQuick的信号处理机制会调用相应的信号处理程序。在实际QtQuick使用中,则可以在处理程序中放置相应逻辑(例如脚本或其他操作),从而能使组件响应事件。
二、用信号处理程序接收信号
要在为特定对象发出特定信号时接收通知,对象定义应该声明一个名为on< Signal >的信号处理程序,其中< Signal >是信号的名称(注意:首字母必须大写)。信号处理程序应该包含在调用信号处理程序时要执行的JavaScript代码。
三、属性改变信号处理程序
当QML属性的值发生变化时,将自动发出信号。这种类型的信号是属性更改信号,这些信号的信号处理程序以on< Property >Changed的形式编写,其中< Property >是属性的名称,第一个字母必须大写。
四、信号参数
在有些使用场景中,信号可能会带有参数。要访问这些参数,应该给处理程序分配一个函数。
4-1、信号定义
在QML中定义一个信号,格式如下:
signal <name>[([<type> <parameter name>[, ...]])]
在Qt C++中,我们使用emit
关键字发出信号;在QML中,发出信号是通过将信号作为方法调用来实现的。
注意:在同一类型块中声明两个具有相同名称的信号或方法是错误的。但是,新信号可能会在该类型上重用现有信号的名称。
如下代码,是定义一个信号的示例
//ReturnBtn.qml 文件
//此处定义一个msgChange信号,该信号带有一个sting类型的参数name,还有一个int类型的参数age
signal msgChange(name:string,age:int)
MouseArea {
anchors.fill: returnIcon_128
onClicked: {
//当点击MouseArea对象类型时,调用msgChange函数,并传入”iriczhao“和999两个参数
msgChange("iriczhao",999)
}
onPressed: {
glow.visible = true
glow.color = "lightskyblue"
}
onReleased:{
glow.visible = false
}
}
4-2、定义信号处理函数接收信号参数
//test.qml文件
Window {
id: window
width: 640
height: 480
visible: true
color: "#4c79ef"
title: qsTr("Hello World")
ReturnBtn {
id: returnBtn
x: 245
y: 204
width: 100
height: 47
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
//此处在msgChange信号处理函数中,使用function()来接收msgChange信号带入的两个参数
onMsgChange: function(name,age){console.log("recv " + name + " " + age)}
}
}
1、函数中形式参数的名称不必与信号中的名称相匹配。
2、如果信号处理程序不需要处理所有的参数,可以省略后面的参数。例如:只想在onMsgChange信号处理函数中接收name参数,不接受age参数,可以这样写:
onMsgChange: function(name){console.log("recv " + " " + name)}
3、对于function()
中不需要的参数,可以使用下划线(_)来进行参数占位,从而告诉qml引擎忽略掉该参数。例如,如果不想在onMsgChange信号处理函数中接收name参数,可以这样写:
onMsgChange: function(_,age){console.log("recv " + " " + age)}
五、使用Connections类型创建信号连接
从上文我们已经知道,当在QML中连接信号时,通常是创建一个on<Signal>
的处理程序,当接收到信号的时候这个信号处理函数会被执行。
然而,在某些情况下使用该种方法连接信号和处理函数是不可能的,例如下列三种情况:
(1)需要对同一个信号进行多个连接。
(2)在信号发送器范围之外创建连接。
(3)连接到QML中未定义的目标。
这时候,我们则可以使用Connections
类型来连接信号和信号处理函数。例如下列代码:
MouseArea {
id: area
}
上述代码定义了一个鼠标点击区域,id为area,我们可以使用Connections关联该类型对象的clicked信号:
Connections {
target: area
function onClicked(mouse) { foo(mouse) }
}
六、连接信号处理函数
附加的信号处理程序从附加类型接收信号,而不是从声明处理程序的对象接收信号。
例如,Component.onCompleted是一个附加的信号处理程序。它通常用于在创建过程完成时执行一些JavaScript代码。例如下面代码:
import QtQuick 2.0
import QtQuick.Window 2.15
import "Components"
Window {
id: window
width: 640
height: 480
visible: true
color: "#4c79ef"
title: qsTr("Hello World")
ReturnBtn {
id: returnBtn
x: 245
y: 204
width: 100
height: 47
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
onMsgChange: function(name){console.log("recv " + " " + name)}
//附加的信号处理函数
Component.onCompleted: {
console.log("ReturnBtn")
}
}
//附加的信号处理函数
Component.onCompleted: {
console.log("Window")
}
}
这里将打印出:
qml: Window
qml: ReturnBtn
(注,这里怎么先打印出Window,然后再打印出ReturnBtn呢,这一点与qml的对象树相关)
七、使用connect将信号连接到方法和信号
注意:本文中connect
与Connections
的区别:connect是对象的一个方法,Connections是一个QML类型。
7-1、将信号连接到方法
信号对象有一个connect()方法用来将信号连接到一个方法或信号。当一个信号连接到一个方法时,只要发出信号,该方法就会被自动调用。这种机制使信号可以由方法而不是信号处理程序接收。
那么,这里来重新修改一下ReturnBtn.qml 文件。如下代码:
Window {
id: window
width: 640
height: 480
visible: true
color: "#4c79ef"
title: qsTr("Hello World")
ReturnBtn {
id: returnBtn
x: 245
y: 204
width: 100
height: 47
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
}
Component.onCompleted: {
//在该组件加载完成信号处理函数中创建:returnBtn对象的msgChange信号与masChangeHandler JavaScript的函数连接。
returnBtn.msgChange.connect(msgChangeHandler)
}
//定义msgChangeHandler函数
function msgChangeHandler(message,value)
{
console.log("recv param :" + message +" " + value);
}
}
在许多情况下,通过信号处理程序接收信号就足够了,而不必使用connect()函数。但是,使用connect方法允许多个方法接收信号,如前面所示,这对于信号处理程序是不可能的,因为信号处理程序命名必须唯一。
此外,connect方法在将信号连接到动态创建的对象时也很有用。
注意:可以使用disconnect()函数断开信号与方法的连接。如下代码:
function removeMsgChangeSignal(){
returnBtn.msgChange.disconnect(msgChangeHandler)
}
经实践:发现如果一个信号同时关联信号处理函数和使用connect()函数关联的方法时,会有问题,所以在实际使用中不允许这种操作。
7-2、将信号连接到信号
在QML中,也可以将信号连接到其他信号,可以使用connect()
方法形成不同的信号链。此处依然修改ReturnBtn.qml文件,如下代码:
Window {
id: window
width: 640
height: 480
visible: true
color: "#4c79ef"
title: qsTr("Hello World")
//定义returnBtnClicked信号
signal returnBtnClicked()
ReturnBtn {
id: returnBtn
x: 245
y: 204
width: 100
height: 47
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
}
Component.onCompleted: {
returnBtn.msgChange.connect(returnBtnClicked)
}
onReturnBtnClicked:
{
console.log("this is Window signal : returnBtnClicked handler")
}
}
这样在点击ReturnBtn按钮后,会打印:
this is Window signal : returnBtnClicked handler
八、总结
本文描述了QML开发中,几种信号和信号处理的方法。在Qt提供的QML类型中,许多类型都有自己的信号。信号处理程序有着一个特定的命名规范:on<Signal>。如果需要一个信号创建多个连接,则可以使用Connections
类型实现。也可以使用对象类型的connect()
方法实现一个信号触发另一个信号,也可以将信号连接到方法。