8

QML 信号与响应方法的总结 - englyf八戒

 1 year ago
source link: https://www.cnblogs.com/englyf/p/16748191.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

以下内容为本人的著作,如需要转载,请声明原文链接 微信公众号「englyf」https://www.cnblogs.com/englyf/p/16748191.html


如果面试过程中,面试官想了解你对 Qt 的理解有多少,少不了会涉及到信号槽这一块,毕竟这是 Qt 最经典的一项技术。

刚开笔,我可能有点狂妄了。

信号槽,分为两部分,信号和对信号响应的槽函数。在可视化开发过程中,无论你用 QWidget 还是 QtQuick 都可以运用到信号槽。QtQuick 是目前 Qt 公司主推的可视化框架了,当然不会缺失对信号槽的支持。

QtQuick 的模块提供了丰富的预定义信号,当然也允许用户自定义信号。

下面就斗胆总结一下在 QML 中信号槽的使用。

1. QtQuick 提供的预定义信号

这些信号都是Qt库里已经预定义好了的,为了使用这些信号,我们需要的是导入类型所在模块和定义响应过程即可。

上来就手掰一个栗子:比如,为了响应 MouseArea 的 clicked 信号,仅需要在 MouseArea 类型对象声明中添加以下形式的语句即可:

onClicked: {
    // do something ....
}

on后边紧跟着的信号名字 clicked 必须首字母大写。冒号后边如果仅是单语句,可以不用大括号{},多语句结尾可以添加分号;结尾。

提醒一下,这种对信号槽的使用方式,适用于信号所属对象的内部。因为这里边其实是包含了隐式的连接(信号和槽),在信号 signal 所属对象的内部直接声明槽函数。

槽函数声明,一般形式如下:

on<Signal>: {
    // do something ....
}

signal 首字母要大写。

2. 属性变化时会触发信号

假设声明了一自定义属性 property,当这个属性被修改后,QML 引擎会发射形式如下的信号

<property>Changed

可添加以下形式语句响应这个属性的变化:

on<Property>Changed: {
    // do something ....
}

在声明响应时,属性名 property 同样需要首字母大写。

无论是自定义的属性,还是预定义的属性,变化时引擎都会发射信号,这些信号响应的形式和上面信号的类似,只不过需要多加个 Changed

3. 附加类型对象Component的信号

简单点理解,QML 引擎会自动在 QML 文件里声明的对象中附加一个 Component 对象。当 QML 文件定义的顶层对象加载完成时,会触发 Component 对象的 completed 信号,为了响应此信号,可以添加以下形式语句:

Component.onCompleted: {
    // do something ....
}

关于 Component 更多信息可以参考

https://doc.qt.io/qt-6/qml-qtqml-component.html

4. 自定义信号

大多数时候,定义的 QML 对象都会需要在其中添加或多或少的自定义信号,同时也会需要定义相应的响应。

用以下形式声明自定义的信号

signal <name>[([<type> <parameter name>[, ...]])]

一般可视化的自定义的 QML 对象都会基于 Item 或者 Rectangle 来做扩展,包括添加自定义信号以及其它必要的功能等,其实这个过程也相当于对原有的类型做了派生(参考C++的习惯)。

Rectangle {
    id: root

    signal mysignal(int x, int y)

    MouseArea {
        anchors.fill: parent
        onPressed: root.mysignal(mouse.x, mouse.y)
    }
}

上面代码中,Rectangle 对象定义了信号 mysignal,带有整形参数x和y。然后添加了针对鼠标区域定义的组件 MouseArea,在其中通过信号槽去触发父对象的自定义信号 mysignal。

MouseArea 属于预定义类型,pressed 信号自带参数 mouse。更多信息可以参考下面的链接:

https://doc.qt.io/qt-6/qml-qtquick-mousearea.html#pressed-signal

自定义信号的处理形式和预定义信号一致,参考上面预定义信号的响应方法。

5. 通过信号的方法connect指定响应

关于 connect,简单的说,就是用于针对具体信号指定响应的方法或者触发的下一个信号。啰嗦点来讲,一个信号被触发了,那么它可以指定响应的方法,也可以指定触发下一个信号形成信号的连锁反应,这个过程就通过 connect 来指定。

如果你熟悉 Qt, 应该对 C++ 的 QObject::connect 方法不陌生。和 C++ 部分类似,QML 中也有 connect 方法,可以连接任意的(包括多个)信号和方法,但是 QML 的 connect 更灵活而且调用方式不太一样。不一样的是,C++ 中 QObject::connect 是静态方法,而 QML 的 connect 由信号提供。参考以下形式:

signal.connect(signal / function_name)

要注意一下,QML 对象的信号必须通过对象来引用。

看个例子:

Rectangle {
    id: root

    signal mySignal()
    // 信号响应处理
    onMySignal: console.log("clicked connect mySignal")

    // 普通方法
    function slt_clicked() {
      console.log("clicked connect slt_clicked");
    }

    Component.onCompleted: {
        mousearea.clicked.connect(slt_clicked);
        mousearea.clicked.connect(mySignal);
    }

    MouseArea {
        id: mousearea
        anchors.fill: parent
    }
}

通过上面的代码可知,在引用的组件 Component 的信号 completed 的响应中,通过另一个组件 mousearea 的信号 ( clicked ) 调用 connect 连接父组件的函数 slt_clicked 和信号 mySignal。

如果信号 clicked 带有参数,那么被连接的方法 ( slt_clicked ) 和信号 ( mySignal ) 也应该有同样数目的参数。

当 MouseArea 组件的信号 clicked 被触发后,可以看到下面的输出:

clicked connect slt_clicked
clicked connect mySignal

当然,如果连接不再需要,那么 disconnect 也是不能缺少的。disconnect 的作用和 connect 相反,专用于解绑已有连接,也是通过信号调用。

Rectangle {
    id: relay
    // ... 省略

    function removeSignal() {
        mousearea.clicked.disconnect(slt_clicked);
        mousearea.clicked.disconnect(mySignal);
    }
}

6. 处理任意对象的信号:

QtQuick 框架提供了一个超级好用的类型:Connections,它可以用于响应任意对象的信号(官方说法是generalized)。

大多数情况下,用于连接其它 QML 文件中定义的对象的信号,具体需要指定信号所属对象的 id。参考以下形式:

import QtQml

Connections {
    target: object_id

    onSignal: {
        // do something ....
    }
}

target 属性用于指定响应信号所属对象的 id。


好了,暂时介绍到这里,下回见......


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK