qml的信号槽机制和qtwidget差不多,但是使用方法不一样,qtwidget一般直接用connect函数把信号和槽一绑定就完事了,qml分为自动绑定和手动绑定。
信号自动绑定
在一个组件里面定义一个信号,用signal定义,当事件触发,比如button的onclick,发送信号,连接信号槽,就是这个信号发出后对他进行一个处理,边看例子边讲吧
//测试qml的信号槽机制
import QtQuick
import QtQuick.ControlsWindow {width: 640height: 480visible: truetitle: qsTr("Hello World")//文本框Flickable {id: flickableanchors.centerIn: parentwidth: 200height: 200contentWidth: textEdit.widthcontentHeight: textEdit.heightclip: true
//滑动条部份,需要用flickable或者scrollbar包装起来ScrollBar.vertical: ScrollBar {id: vbarwidth: 20policy: ScrollBar.AsNeededanchors {right: parent.righttop: parent.topbottom: parent.bottom}}TextEdit {id: textEditwidth: flickable.widthheight: Math.max(flickable.height, implicitHeight)wrapMode: TextEdit.Wrapcolor: "red"}}//测试信号按钮Button{x:10y:10width: 40height: 20text: "btn1"signal haveClick()onClicked: {haveClick()}onHaveClick: {textEdit.append("btn1被点击")}}}
上面这段代码,我定义了一个文本框和一个按钮,文本框有一个滑动条模块,注意下,滑动条需要用scrollview或者flickable包装一下,button中定义了一个信号haveclick(),当按钮被点击onclick的时候就会被触发发送,发送出去自动绑定就是在信号名前面加上on并把信号名首字母大写,后面跟上处理函数,如上onHaveClick: {textEdit.append("btn1被点击")},textedit是我给文本框定义的id,我希望信号发出后,文本框能加上一行某某被点击,上面的代码可以直接复制到qml文件中区跑着看看,这个就是自动绑定信号槽。上面是信号槽绑定的一种方法,还有一种是类似JavaScript的箭头函数或者c++的lamda函数表达式的。
信号槽的手动绑定
我们在发送者的内部定义信号,在接收者内部定义接收槽函数。信号发出时进行信号槽的绑定
下面是无参和有参的实例
import QtQuick
import QtQuick.ControlsWindow {width: 640height: 480visible: truetitle: qsTr("Hello World")// Component.onCompleted: { print("窗口被创建")}// Component.onDestruction: {print("窗口被销毁")}//接收者,接收信号后打印Rectangle{id:rec// Component.onCompleted: { print("矩形被创建")}// Component.onDestruction: {print("矩形被销毁")}function ptr(){print("接收到按钮信号")}function ptr2(a, b){print(a+b)}}//发送者,触发后发送信号Button{width: 200height: 40x:50y:50text: "发送信号"signal testsignalsignal test2(int a,int b)onClicked: {testsignal()test2(1,2)}onTestsignal: ()=>{rec.ptr()}onTest2: (a,b)=>{rec.ptr2(a,b)}//有参信号连接的第二种方法亲测无效,避雷//onTest2: rec.ptr2}}
还有一种连接方式
onClicked: {parent.testsignal.connect(rec.ptr)parent.test2.connect(rec.ptr2)}
一般不会这么用,只是理解下用法,这里可能有重复链接的问题,qml5的用法,在qml6中已经废除,qml6中改用connections,这里需要注意
QML5中的connections基本用法
import QtQuick 2.15
import QtQuick.Controls 2.15Item {signal mySignal()Button {text: "触发信号"onClicked: mySignal()}Text {id: statusTexttext: "未收到信号"}// QML5 风格的 ConnectionsConnections {target: parent // 连接到此对象发出的信号onMySignal: {console.log("信号已接收")statusText.text = "已接收信号!"}}
}
QML5的connections没有enable属性
QML6的基本用法
Connections {target: sourceObject // 发出信号的对象enabled: true // 可选,控制连接是否激活// 信号处理器 - 方式1:函数声明function onSignalName(param1, param2) {// 处理逻辑}// 信号处理器 - 方式2:Lambda表达式onAnotherSignal: (param) => {// 处理逻辑}
}
组件的创建和销毁
每个组件其实都有两个信号,类似c++中类的构造函数和析构函数
Component.onCompleted:{}//组件的构造
Component.onDestruction: {}//组件的析构
在他们初始化和销毁的时候就会发生
import QtQuick
import QtQuick.ControlsWindow {width: 640height: 480visible: truetitle: qsTr("Hello World")Component.onCompleted: { print("窗口被创建")}Component.onDestruction: {print("窗口被销毁")}Rectangle{Component.onCompleted: { print("矩形被创建")}Component.onDestruction: {print("矩形被销毁")}}
}
运行效果:
按钮点击后控制台输出:
在一个窗口里面创建一个矩形,窗口就是矩形的父对象,看看运行结果
初始化的时候是父节点先创建,在创建子节点,程序销毁的时候是子节点先被销毁,再是父节点被销毁,和qtwidget的对象树一样