QML学习笔记(二十一)QML的跨组件发送信号
前言
本节我们将学习跨组件间的信号通信。我们已经学过自定义组件和自定义信号相关的内容,我们将对这些知识做进一步的应用。
思路是这样的,我们先实现两个自定义组件,称为通知器和接收器。然后我们通过信号槽绑定方式来连接他们。
通知器和接收器都是矩形对象,我期望点击通知器矩形时,能让接收器矩形中的文本数字添加1,这很好理解,对吧?
新建工程QmlSignalsAcrossComponents,然后开始实现吧。
一、自定义组件-Notifier
import QtQuick 2.0Item {property alias rectColor: notifierRectId.colorwidth: notifierId.widthheight: notifierId.heightproperty int count: 0signal notify(string count)Rectangle{id: notifierRectIdwidth: 200height: 200color: "red"Text {id: displayTextIdanchors.centerIn: parentfont.pointSize: 20text: count}MouseArea{anchors.fill: parentonClicked: {count++notify(count)}}}
}
因为内容比较简单,且都是之前学习过的内容,我就不多赘述了。
这里鼠标点击的时候,会递增count,并将它通过notify信号发送出去。
我们简单在main.qml中实现一下,看看效果:
import QtQuick 2.14
import QtQuick.Window 2.14Window {visible: truewidth: 640height: 480title: qsTr("QmlSignalsAcrossComponents")Notifier{id: notifierIdrectColor: "yellowgreen"onNotify: count=> {console.log("Received: " + count)}}
}
可以看到,矩形的颜色可以修改,点击后数字会叠加,打印信息也正常。
二、自定义组件-Recevier
仿照刚才的代码,稍作修改:
import QtQuick 2.0Item {property alias rectColor: receiverRectId.colorwidth: receiverRectId.widthheight: receiverRectId.heightfunction receiveInfo(count){displayTextId.text = count}Rectangle{id: receiverRectIdwidth: 200height: 200color: "red"Text {id: displayTextIdanchors.centerIn: parentfont.pointSize: 20text: "0"}}
}
function receiveInfo(count){
displayTextId.text = count
}
这里主要是准备了一个函数,之后在main中进行槽连接。
main.cml中创建Recevier的对象:
Receiver{id: receiverIdrectColor: "dodgerblue"anchors.right: parent.right}
三、跨组件的发送信号
Component.onCompleted: {notifierId.notify.connect(receiverId.receiveInfo)}
最后,我们在附加信号处理器中进行信号槽连接。
运行效果看看:
完美实现点击绿色矩形,蓝色矩形的数字也一起叠加的效果。
四、第二种连接方式(Qt6.2)
因为我只有qt5,所以没办法演示了,只能学习以下吧。
这里先对Notifier进行了修改,这种写法大概是说,它需要一个Receiver类型的属性,相当于在这个组件内部,创建了一个Receiver对象的指针。
这种写法明显存在紧密耦合的问题。
再然后,我们在main中修改代码:
可以看到,这里给Notifier指定了target的id。指定的时候相当于修改了target,所以就触发onTargetChanged,也就实现了信号槽连接。
之后应该就能实现我们想要的功能了。
五、传递多个信号参数
到目前为止,我们都只使用过一个信号参数的信号。但实际上,信号是可以传递多个参数的,这一点和QWidget中的信号槽也是一样的。
我们基于刚才的Notifier和Receiver,设计一个多参数的信号。
先给Notifier添加一个新的信号:
signal info(string last_name, string first_name, string age)
这个信号可以传递一个人的姓氏、名字和年龄。
然后我们在Receiver中设置一个新的函数:
function recv_info(l, f, a){displayTextId.text = l + f + a}
这个函数会简单拼接着三个字符串,并显示在矩形中。
最后,我们在main.qml中设置信号槽连接:
Component.onCompleted: {// notifierId.notify.connect(receiverId.receiveInfo)notifierId.info.connect(receiverId.recv_info)}
然后我们看运行现象:
点击之后,名字果然显示在右侧矩形上,符合预期。
这里还要将一下信号参数省略的问题,事实上,槽函数和信号的参数数量可以是不一致的。
让我们测试几种情形:
信号:
signal info(string last_name, string first_name, string age)
槽函数1(正常):
function recv_info(l, f){displayTextId.text = l + f}
效果:
槽函数2:
function recv_info(f, a){displayTextId.text = f + a}
这里试图隐藏第一个参数,但这是没有意义的,不过是参数名换了而已。
这当然也可以运行,只不过和第一种情况一样,但这并不符合你的语气。
槽函数3:
function recv_info(_, f, a){displayTextId.text = f + a}
使用下划线的占位符是正确的做法。
六、总结
本节我们详细实践了跨组件发送信号的方式,并且学习了省参写法的信号。至此,我们应该对QML的信号槽有一定的理解,特别是我们本身就有QWidget的基础,这将帮助我们在后续开发复杂的组件逻辑时提供可能。