QML信号和信号处理器程序

简介: 简述信号和槽作为 Qt 的核心机制,在 Qt 编程中有着广泛的应用。同样,QML 也继承了这样的特性 - 信号和信号处理程序 ,只不过叫法上略有不同。信号:来自 QML 对象的通知。信号处理程序:由信号触发的表达式(或函数),也被称为 Qt C++ 中的“槽”。信号是事件,信号通过信号处理程序来响应。当一个信号被发射时,相应的信号处理程序就会被调用,在处理程序

简述

信号和槽作为 Qt 的核心机制,在 Qt 编程中有着广泛的应用。同样,QML 也继承了这样的特性 - 信号和信号处理程序 ,只不过叫法上略有不同。

  • 信号:来自 QML 对象的通知。
  • 信号处理程序:由信号触发的表达式(或函数),也被称为 Qt C++ 中的“槽”。

信号是事件,信号通过信号处理程序来响应。当一个信号被发射时,相应的信号处理程序就会被调用,在处理程序中放置逻辑(例如:脚本或其他操作)以允许组件响应事件。

版权所有:一去丶二三里,转载请注明出处:http://blog.csdn.net/liang19890820

使用信号处理程序接收信号

信号是来自对象的通知,表示发生了某些事件(例如:鼠标已点击、属性已更改、动画已启动/停止)。每当特定信号被发射时,若要接收通知:

  • 对象定义应声明一个名 on<Signal> 的信号处理程序,其中 <Signal> 是信号的名称,首字母大写。
  • 信号处理程序必须在发出信号的对象定义中声明,并且处理程序应包含调用时要执行的 JavaScript 代码块。

例如,MouseArea 类型有一个 clicked 信号,无论何时在该区域内单击鼠标都会发出该信号。由于信号名称是 clicked,所以接收该信号的信号处理程序应命名为 onClicked

下面的示例中,每当鼠标区域被点击时,onClicked 处理程序就会被调用,为 Rectangle 分配一个随机颜色:

import QtQuick 2.3

Rectangle {
    id: rect
    width: 100; height: 100

    MouseArea {
        anchors.fill: parent
        onClicked: {  // 鼠标单击
            rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);
        }
    }
}

查看 MouseArea 文档,可以看到 clicked 信号发出时带有一个名为 mouse 的参数,这是一个 MouseEvent 对象,包含了有关鼠标单击事件的很多详细信息,可以在 onClicked 处理程序中引用该名称来访问此参数。

例如,MouseEvent 类型有 x 和 y 坐标,这使我们可以打印出鼠标点击的确切位置:

import QtQuick 2.3

Rectangle {
    id: rect
    width: 100; height: 100

    MouseArea {
        anchors.fill: parent
        onClicked: {  // 鼠标单击
            rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);

            // 访问 mouse 参数
            console.log("Clicked mouse at", mouse.x, mouse.y)
        }
    }
}

属性改变信号处理程序

当 QML 属性值发生改变时,将自动发出信号。这种类型的信号是属性改变信号,对应的处理程序为属性改变信号处理程序。

  • 属性改变信号处理程序以 on<Property>Changed 的形式写入,<Property> 是属性的名称,首字母大写。

例如,MouseArea 类型具有 pressed 属性,要在该属性改变时接收通知,需要编写名为 onPressedChanged 的信号处理程序:

import QtQuick 2.3

Rectangle {
    id: rect
    width: 100; height: 100

    MouseArea {
        anchors.fill: parent
        onPressedChanged: {  // 鼠标按下/释放
            console.log("Mouse area is pressed?", pressed)
        }
    }
}

尽管 MouseArea 文档中没有记录名为 onPressedChanged 的信号处理程序,但是因为存在 pressed 属性,所以它也被隐式地提供了。

使用 Connections 类型

QtQuick 模块提供了 Connections 类型,用于连接到任意对象的信号。Connections 的优点是:

  • 可以在发射信号的对象外部访问该信号

例如,上述示例中的 onClicked 处理程序可以由根 Rectangle 接收,只需要将其放置在一个 Connections 对象中,并指定 target 为 mouseArea:

import QtQuick 2.3

Rectangle {
    id: rect
    width: 100; height: 100

    MouseArea {
        id: mouseArea
        anchors.fill: parent
    }

    Connections {
        target: mouseArea
        onClicked: {
            rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);
        }
    }
}

附加信号处理程序

附加信号处理程序所接收的信号来自附加类型,而非声明处理程序的对象。

附加,也称为额外。可以简单理解为:对象本身或其基类没有的属性和信号,需要通过外部(附加类型)提供。

要引用附加属性和处理程序,可以使用以下语法形式:

  • <AttachingType>.<propertyName>
  • <AttachingType>.on<SignalName>

例如,下面的 Item 可以通过附加类型 Keys 来访问其附加属性和附加信号处理程序:

import QtQuick 2.3

Item {
    width: 100; height: 100

    focus: true
    Keys.enabled: true
    Keys.onReturnPressed: console.log("Return key was pressed")  // 按下回车键,打印 log 信息
}

enabled 是 Keys 的一个属性,为其赋值为 true(默认值是 true,这里主要用于说明如何使用附加类型的属性),表明启用键盘处理。

由于 Keys 提供了 returnPressed 信号,所以可以通过 onReturnPressed 来引用相应的附加信号处理程序。

类似的附加类型还有很多,例如:Component,它有一个 onCompleted 附加信号处理程序,通常用于在创建完成后执行某些 JavaScript 代码:

import QtQuick 2.3

Rectangle {
    width: 200; height: 200
    color: Qt.rgba(Qt.random(), Qt.random(), Qt.random(), 1)

    Component.onCompleted: {
        console.log("The rectangle's color is", color)
    }
}

onCompleted 处理程序没有响应来自 Rectangle 类型的 completed 信号。相反,Component 对象由 QML 引擎自动附加到 Rectangle 对象,当对象完全创建时,引擎发出 completed 信号,从而触发 Component.onCompleted 信号处理程序。

附加信号处理程序允许向对象通知有意义的特定信号。如果没有为某个特定对象注册信号,那么就不能接收相应的通知,附加信号处理机制使得对象能够接收特定的信号而无需这些额外的处理。

自定义信号

当自定义类型不可避免,当现有信号无法满足,这时,最好的方法就是自定义信号。

可以通过 signal 关键字来添加自定义信号,语法如下:

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

例如,下面声明了三个自定义信号:

import QtQuick 2.3

Item {
    signal clicked
    signal hovered()
    signal actionPerformed(string action, var actionResult)
}

如果信号没有参数,括号“()” 是可选的;倘若有参数,那么必须声明参数的类型(正如上述 actionPerformed 信号中的 string 和 var 一样)。

要发射信号,可以将其作为方法来调用。任何相关的信号处理程序将在发出信号时被调用,处理程序可以使用定义的信号参数名称来访问相应的参数。

例如,假设下面的代码被定义在一个名为 SquareButton.qml 的文件中,根 Rectangle 对象有一个 activated 信号。当子 MouseArea 被点击时,它会以鼠标点击的坐标发出 parent 的 activated 信号:

// SquareButton.qml
Rectangle {
    id: root

    signal activated(real xPosition, real yPosition)

    property int side: 100
    width: side; height: side

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

然后,SquareButton 的任何对象都可以使用 onActivated 信号处理程序连接到 activated 信号:

// myapplication.qml
SquareButton {
    onActivated: console.log("Activated at " + xPosition + "," + yPosition)
}

信号到方法/信号的连接

大部分情况下,通过信号处理程序接收信号就足够了,然而,要将信号连接至多个方法/信号,这对于信号处理程序来说是不可能的(因为信号处理程序的命名必须唯一)。

在 Qt C++ 中,信号与槽的连接方式使用的是 QObject::connect()。相应地,在 QML 中,signal 对象也有一个 connect() 方法,用于将信号连接到一个方法或另一信号。当信号连接到方法时,无论信号何时发出,该方法都将被自动调用。有了这种机制,可以通过方法来接收信号,而无需使用信号处理器。

所以呢,相对于信号处理程序来说,connect() 更加灵活:

  • 可以将信号连接至多个方法/信号

此外,当将信号连接到动态创建的对象时,connect() 方法也很有用。

信号到方法的连接

下面,使用 connect() 方法将 messageReceived 信号连接到两个方法:

import QtQuick 2.3

Rectangle {
    id: relay

    signal messageReceived(string message, string qq)

    Component.onCompleted: {
        relay.messageReceived.connect(sendToLiLei)  // 连接信号和方法
        relay.messageReceived.connect(sendToHanMeimei)  // 连接信号和方法
        relay.messageReceived("Welcome to join us(QML分享&交流)", "26188347")  // 发射信号
    }

    function sendToLiLei(message, qq) {
        console.log("Sending to LiLei: " + message + ", " + qq)
    }
    function sendToHanMeimei(message, qq) {
        console.log("Sending to HanMeimei: " + message + ", " + qq)
    }
}

广播一下,李雷和韩梅梅就可以很快的找到组织了~O(∩_∩)O~!

有 connect() 方法,必然也会有相应的 disconnect() 方法,用于删除连接的信号:

Rectangle {
    id: relay
    //...

    function removeLiLeiSignal() {
        relay.messageReceived.disconnect(sendToLiLei)
    }
}

用法很简单,和 connect() 相同。

信号到信号的连接

通过将信号连接到其他信号,connect() 方法可以形成不同的信号链。

import QtQuick 2.3

Rectangle {
    id: forwarder
    width: 100; height: 100

    signal sendToLiLei()  // 自定义信号
    signal sendToHanMeimei()  // 自定义信号
    onSendToLiLei: console.log("Send to LiLei")  // 信号处理程序
    onSendToHanMeimei: console.log("Send to HanMeimei")  // 信号处理程序

    MouseArea {
        id: mousearea
        anchors.fill: parent
        onClicked: console.log("Clicked")
    }

    Component.onCompleted: {
        // 连接信号至两个信号
        mousearea.clicked.connect(sendToLiLei)
        mousearea.clicked.connect(sendToHanMeimei)
    }
}

每当 MouseArea 的 clicked 信号被发射,sendToLiLei、sendToHanMeimei 信号也将自动发射,从而执行对应的信号处理程序。

这时,输出如下:

Clicked
Send to LiLei
Send to HanMeimei

建议: 在 QML 中,信号和信号处理器程序是一个核心机制,一定要熟练掌握。。。Good Luck!

目录
相关文章
|
2月前
(8)Qt中的自定义信号
本文介绍了如何在Qt框架中创建和使用自定义信号,并通过一个父子窗口切换的示例来展示自定义信号的实现和应用。
103 3
(8)Qt中的自定义信号
|
4天前
|
传感器 安全
第四问:QT中信号和槽原理
Qt的信号与槽机制是观察者模式的典型实现,允许对象间通信而不直接依赖。信号用于通知事件发生,槽是响应信号的函数,通过`QObject::connect()`连接。这种机制实现了松耦合、灵活扩展和自动通知,适用于UI更新和数据绑定等场景。
18 1
|
3月前
|
Linux C语言
C语言 多进程编程(四)定时器信号和子进程退出信号
本文详细介绍了Linux系统中的定时器信号及其相关函数。首先,文章解释了`SIGALRM`信号的作用及应用场景,包括计时器、超时重试和定时任务等。接着介绍了`alarm()`函数,展示了如何设置定时器以及其局限性。随后探讨了`setitimer()`函数,比较了它与`alarm()`的不同之处,包括定时器类型、精度和支持的定时器数量等方面。最后,文章讲解了子进程退出时如何利用`SIGCHLD`信号,提供了示例代码展示如何处理子进程退出信号,避免僵尸进程问题。
|
3月前
|
Linux C语言
C语言 多进程编程(三)信号处理方式和自定义处理函数
本文详细介绍了Linux系统中进程间通信的关键机制——信号。首先解释了信号作为一种异步通知机制的特点及其主要来源,接着列举了常见的信号类型及其定义。文章进一步探讨了信号的处理流程和Linux中处理信号的方式,包括忽略信号、捕捉信号以及执行默认操作。此外,通过具体示例演示了如何创建子进程并通过信号进行控制。最后,讲解了如何通过`signal`函数自定义信号处理函数,并提供了完整的示例代码,展示了父子进程之间通过信号进行通信的过程。
|
4月前
【qt】QTcpSocket相关的信号
【qt】QTcpSocket相关的信号
27 0
|
5月前
|
C++
Qt中的信号与槽如何学习?(包括自定义信号)这篇文章告诉你
以现实中的事件来举例的话,例如有两把不同颜色的信号枪,分别是红色,绿色,打响不通颜色的信号枪会触发不同的槽发生,比如说打响红色这个人就跑步,绿色就走步,但是还有一个很重要的机制,那就是连接,我们需要把信号枪去跟这个人的动作连接起来。 如果上面理解没问题的话我们可以把信号和槽看成两个工具,我们最重要的是如何去把这两个工具连接起来。 它的作用可以让我们更加灵活的去使用不同窗口间的切换以及某些事件的连接。
112 0
|
7月前
|
JavaScript 前端开发 安全
【QML 与 C++ 之间的通讯机制】QML 与 Qt 通讯:讲解如何在QML 中使用C++类,以及如何在C++ 中获取QML的内容
【QML 与 C++ 之间的通讯机制】QML 与 Qt 通讯:讲解如何在QML 中使用C++类,以及如何在C++ 中获取QML的内容
801 1
|
Unix Linux
Linux系统应用编程 --- 信号处理函数(sigaction实现信号捕捉设定)
Linux系统应用编程 --- 信号处理函数(sigaction实现信号捕捉设定)
132 0