跳转到内容
新建笔记

QML Connections:信号参数、动态目标与监听寿命

Connections 把信号监听逻辑放到一个独立对象中。它适用于不能直接在发送者声明里写处理器、多个对象监听同一信号,或运行时切换发送者的情况。可以直接写在发送者里的 onClicked 并没有失效;两种写法服务于不同的组织方式。

本文使用 Qt 6.10 和显式 function onSignalName(...) 语法。Connections 由 QtQml 提供,界面与控件分别来自 QtQuick、QtQuick.Controls。

名称含义例子
信号发送者定义并发出的事件clicked、valueChanged、submitted(string message)
直接处理器写在发送者对象内onClicked: ...
Connections 中的方法连接目标信号的处理函数function onSubmitted(message) { ... }

处理函数的参数必须对应真实信号签名;不能把 param1, param2, ... 这种说明性占位符直接复制进程序。旧写法 onSignal: { ... } 不应与同一 Connections 中的 function onSignal(...) 混用;统一使用函数写法。

完整例子:两个发送者、动态目标和两个监听器

跳转到“完整例子:两个发送者、动态目标和两个监听器”

保存为 ConnectionsDemo.qml。点击“发送”会发出当前发送者的自定义信号;勾选切换发送者,两个监听器都会随 target 绑定改变而重新连接。关闭“监听”后,旧信号不会缓存起来等待恢复。

import QtQml
import QtQuick
import QtQuick.Controls
Item {
id: root
width: 420
height: 260
property bool useSecond: false
property bool listening: true
property int received: 0
property int auditCount: 0
property string lastMessage: "none"
property QtObject activeSender: root.useSecond ? second : first
QtObject {
id: first
signal submitted(string message)
}
QtObject {
id: second
signal submitted(string message)
}
Connections {
target: root.listening ? root.activeSender : null
function onSubmitted(message) {
root.received += 1
root.lastMessage = message
}
}
Connections {
target: root.activeSender
enabled: root.listening
function onSubmitted(message) {
root.auditCount += 1
}
}
Column {
spacing: 12
CheckBox {
text: "使用第二个发送者"
checked: root.useSecond
onToggled: root.useSecond = checked
}
CheckBox {
text: "监听"
checked: root.listening
onToggled: root.listening = checked
}
Button {
text: "发送"
onClicked: root.activeSender.submitted(root.useSecond ? "second" : "first")
}
Text {
text: root.lastMessage + " / received=" + root.received
+ " / audit=" + root.auditCount
}
}
}

target 的默认值是 Connections 的父对象;独立监听时显式设置更易读。target: null 暂时不连接任何对象,enabled: false 暂停该连接的响应。动态目标必须具有处理器所指的信号;若某些目标故意没有该信号,可考虑 ignoreUnknownSignals: true,但它也会掩盖信号名拼错,不宜作为默认补救。

同一信号可以由多个 Connections 监听,Connections 也可以处理一个目标的多个不同信号。不应依赖多个监听器的执行次序来组织关键业务;需要严格顺序时,在一个明确的处理函数中调用相应步骤。

属性通知不保证带着新值

跳转到“属性通知不保证带着新值”

原稿把 Slider.valueChanged 写成带 value 参数的普通信号。Qt Quick Controls 的 valueChanged 是该属性的无参数通知;处理器应从目标读取 value。若需要显式负载,可以像上例那样自行声明带参数的信号。

保存为 SliderConnection.qml:

import QtQml
import QtQuick
import QtQuick.Controls
Item {
id: root
width: 360
height: 120
property real observedValue: 0
property int notifications: 0
Slider {
id: slider
objectName: "slider"
width: parent.width
from: 0
to: 100
value: 0
}
Connections {
target: slider
function onValueChanged() {
root.observedValue = slider.value
root.notifications += 1
}
}
Text {
anchors.top: slider.bottom
text: "value=" + root.observedValue.toFixed(1)
}
}

程序设置 slider.value 也可能触发属性通知。要区分用户操作和程序修改,应阅读控件的交互信号,例如 Slider.moved,不能仅凭名称 valueChanged 判断来源。

target 也可以是已向 QML 暴露的 QObject,前提是其类型和对象生命周期正确,信号进入 Qt 元对象系统。C++ 信号 void completed(QString result); 对应 function onCompleted(result) { ... },这里的参数来自该 C++ 签名,不是从处理器名称推测。若目标销毁或更换,必须同时保证持有该目标的属性正确更新;不要保留自己在 JavaScript 中缓存的失效业务引用。

完整语言规则见 Qt 6.10 Connections,控件接口见 Slider。附加信号如 Component.onCompleted 的对象作用域另见附加属性与生命周期。