QML 信号与槽:直接绑定与跨文件通信

这篇介绍 QML 内部两种最常见的信号用法:控件属性变化时直接响应,以及把多个 QML 文件里的组件串起来通信。

  • 直接绑定 --- 用 onValueChanged 响应 Slider 数值变化
  • 跨文件通信 --- 用 connect 把 CustomSender 的信号接到 CustomReceiver 的槽函数

Demo 1 直接绑定

移动 Slider 滑块时,下方 Text 实时显示当前数值。

演示代码

qml 复制代码
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

FadeInAnimation {
    id: root

    property string respMsg: ""

    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 20
        spacing: 15

        // ... 省略标题组件 TitleSeparator ...

        Rectangle {
            Layout.fillWidth: true
            Layout.preferredHeight: 120
            color: "#fff"
            border.color: "#ccc"
            border.width: 1
            radius: 6

            ColumnLayout {
                anchors.fill: parent
                anchors.margins: 10
                spacing: 10

                Text {
                    text: "请移动滑块触发信号: "
                    color: "#333"
                    font.pointSize: 12
                    font.bold: true
                }

                Slider {
                    id: slider
                    Layout.fillWidth: true
                    from: 0
                    to: 100
                    value: 50

                    onValueChanged: {
                        root.respMsg = "滑块数值:" + value.toFixed(2)
                    }
                }

                Text {
                    id: textReceiver
                    text: root.respMsg || "等待显示响应数据 ..."
                    font.pointSize: 11
                    color: "#3498db"
                    wrapMode: Text.WordWrap
                }
            }
        }

        Item { Layout.fillHeight: true }
    }
}

关键逻辑解析

QML 里每个属性都自带一个 <属性名>Changed 信号。Slider 的 value 属性变化时,onValueChanged 处理器就会被触发。

这里把响应逻辑直接写在控件内部,适合一对一、同文件内的简单交互。代码少,关系清晰:滑块动 → respMsg 更新 → Text 刷新。

如果多个地方都要监听这个 value,直接写多个 onValueChanged 会重复。更解耦的做法是把 Slider 的信号 connect 到外部的槽函数,这就是下个 demo 的思路。

Demo 2 跨文件信号通信

CustomSender.qml 发送滑块数值,CustomReceiver.qml 接收并显示,两个组件互不直接引用,靠主文件在初始化时做连接。

演示代码

qml 复制代码
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

FadeInAnimation {
    id: root

    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 20
        spacing: 15

        // ... 省略标题组件 TitleSeparator ...

        CustomSender {
            id: sender
        }

        CustomReceiver {
            id: receiver
        }

        Component.onCompleted: {
           sender.sendValue.connect(receiver.slotReceiveMsg)
        }

        Item { Layout.fillHeight: true }
    }
}

CustomSender.qml:

qml 复制代码
Rectangle {
    id: root
    signal sendValue(real value)

    // ... 省略布局与样式 ...

    Slider {
        id: slider
        from: 0
        to: 100
        value: 50

        onValueChanged: {
            root.sendValue(value)
        }
    }
}

CustomReceiver.qml:

qml 复制代码
Rectangle {
    id: root
    property string message: ""

    function slotReceiveMsg(msg) {
        root.message = "来自sender发送的数据: " + msg.toFixed(2)
    }

    // ... 省略布局与样式 ...

    Label {
        text: root.message || "等待信号发送 ..."
    }
}

关键逻辑解析

跨文件通信的核心是三步:

  1. 发信号 :在 CustomSender.qml 里用 signal sendValue(real value) 声明信号。
  2. 定义槽 :在 CustomReceiver.qml 里用 function slotReceiveMsg(msg) 定义普通函数作为槽。
  3. 做连接 :在主文件 Component.onCompleted 里用 sender.sendValue.connect(receiver.slotReceiveMsg) 把两者连起来。

这样做的好处是发送端和接收端互不知道对方存在,降低耦合。只要信号签名一致,随时可以替换不同的发送端或接收端。

对比表格

场景 推荐方式 原因
同文件内,一对一简单响应 onValueChanged 直接绑定 代码最短,关系直接
跨文件、多对一或需解耦 signal + connect 组件之间不直接依赖,便于复用

运行验证

  1. Qt Creator 打开示例的 CMakeLists.txt;
  2. 按 Ctrl+R 运行;
  3. 在第 1 个 demo 移动 Slider,观察 Text 实时变化;
  4. 切换到第 2 个 demo,移动 Sender 的 Slider,观察 Receiver 同步更新。

扩展复用方向

  • 在 CustomSender 里增加 sendText(string text) 信号,把字符串传给 Receiver。
  • 一个 Sender 的多个信号可以分别 connect 到不同 Receiver,实现一对多广播。
  • 用 disconnect 在页面销毁时断开连接,避免重复触发或内存问题。

已验证环境:

相关推荐
全栈弄潮儿2 小时前
Python实战第6期:列表与元组
后端·python·编程语言
mengzhi啊4 小时前
SerialPortItem对串口再封装一层,省去一些常用的步骤,不用每次都去写类
qt
用户83344239661416 小时前
从批量操作到任务中心,再到现场工作台:DeviceForge v2.10—v2.12 完整演进
qt
Percy_kk17 小时前
AI Agent 开发实践:从手写 ReAct 到框架选型
agent·设计
宛 禾18 小时前
Qt 控件入门:QLabel 从拖拽到对象树,一篇讲透
c++·qt·学习
高晶20 小时前
Android 计算器开发实战:从界面设计到核心逻辑
程序员·设计
易知微EasyV数据可视化21 小时前
会插卡片的编辑器:在 Agent 输入框里混排文字与结构化内容
人工智能·经验分享·编辑器·agent·设计
打工仔折腾 AI1 天前
Qt网络编程实战:UDP、TCP到HTTP的落地经验与选型
网络·人工智能·后端·python·qt·udp·ai agent 实战
Lhan.zzZ1 天前
Linux + Qt/QML:解决 QtQuick.VirtualKeyboard.Plugins 模块加载失败与环境变量配置
linux·数据库·qt
誰能久伴不乏1 天前
QT工业上位机一次「指令静默丢失」的排查
qt·docker·github