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 QtQmlimport QtQuickimport 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 QtQmlimport QtQuickimport 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 判断来源。
C++ 对象作为目标
跳转到“C++ 对象作为目标”target 也可以是已向 QML 暴露的 QObject,前提是其类型和对象生命周期正确,信号进入 Qt 元对象系统。C++ 信号 void completed(QString result); 对应 function onCompleted(result) { ... },这里的参数来自该 C++ 签名,不是从处理器名称推测。若目标销毁或更换,必须同时保证持有该目标的属性正确更新;不要保留自己在 JavaScript 中缓存的失效业务引用。
完整语言规则见 Qt 6.10 Connections,控件接口见 Slider。附加信号如 Component.onCompleted 的对象作用域另见附加属性与生命周期。