【QML】qml信号和事件处理机制总结

一、开篇

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将信号连接到方法和信号

注意:本文中connectConnections的区别: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()方法实现一个信号触发另一个信号,也可以将信号连接到方法。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iriczhao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值