> 技术文档 > qml的信号槽机制

qml的信号槽机制

qml的信号槽机制和qtwidget差不多,但是使用方法不一样,qtwidget一般直接用connect函数把信号和槽一绑定就完事了,qml分为自动绑定和手动绑定。

信号自动绑定

在一个组件里面定义一个信号,用signal定义,当事件触发,比如button的onclick,发送信号,连接信号槽,就是这个信号发出后对他进行一个处理,边看例子边讲吧

//测试qml的信号槽机制import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: true title: qsTr(\"Hello World\") //文本框 Flickable {  id: flickable  anchors.centerIn: parent  width: 200  height: 200  contentWidth: textEdit.width  contentHeight: textEdit.height  clip: true//滑动条部份,需要用flickable或者scrollbar包装起来  ScrollBar.vertical: ScrollBar {  id: vbar  width: 20  policy: ScrollBar.AsNeeded  anchors {  right: parent.right  top: parent.top  bottom: parent.bottom  }  }  TextEdit {  id: textEdit  width: flickable.width  height: Math.max(flickable.height, implicitHeight)  wrapMode: TextEdit.Wrap  color: \"red\"  } } //测试信号按钮 Button{ x:10 y:10 width: 40 height: 20 text: \"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 QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: true title: 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: 200 height: 40 x:50 y:50 text: \"发送信号\" signal testsignal signal 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.15import QtQuick.Controls 2.15Item { signal mySignal() Button { text: \"触发信号\" onClicked: mySignal() } Text { id: statusText text: \"未收到信号\" } // QML5 风格的 Connections Connections { 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 QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: true title: qsTr(\"Hello World\") Component.onCompleted: { print(\"窗口被创建\")} Component.onDestruction: {print(\"窗口被销毁\")} Rectangle{ Component.onCompleted: { print(\"矩形被创建\")} Component.onDestruction: {print(\"矩形被销毁\")} }}

运行效果:

按钮点击后控制台输出:

 

 在一个窗口里面创建一个矩形,窗口就是矩形的父对象,看看运行结果

初始化的时候是父节点先创建,在创建子节点,程序销毁的时候是子节点先被销毁,再是父节点被销毁,和qtwidget的对象树一样