1. 引言

Loader 通过 loader.item 属性访问已加载的组件实例,从而可以读取或修改子组件中声明的 property 属性。本文将介绍如何通过 Loader 实现属性传递,包括:

  • 通过 loader.item 访问加载组件的属性
  • 使用 onLoaded 信号初始化属性值
  • 结合 TextField 和 ComboBox 实现动态属性设置
  • 属性重置与恢复

本文是QML Loader 组件示例合集:

的续篇,介绍第 8 个示例【属性传递】,文章中只显示关键部分,完整代码见下载链接。


2. 演示效果

属性传递示例展示了一个交互式界面,用户可以通过输入文字和选择颜色,动态修改 Loader 加载的组件属性:

在这里插入图片描述

  1. 输入文字:通过 TextField 输入最多 10 个字符的文本
  2. 选择颜色:通过 ComboBox 选择背景颜色(红色、蓝色、绿色、紫色)
  3. 应用:将输入的文字和选择的颜色传递给加载的组件
  4. 重置:恢复默认的文字和颜色

3. 代码说明

3.1 属性传递完整实现

文件:Demo_LoaderProps.qml

关键代码

BaseRect {

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

        Text {
            text: "8. 属性传递"
            font.pointSize: 13
            font.bold: true
        }

        RowLayout {
            Layout.fillWidth: true
            spacing: 10

            TextField {
                id: textInput
                placeholderText: "输入文字"
                Layout.fillWidth: true
                maximumLength: 10
            }

            ComboBox {
                id: colorPicker
                Layout.fillWidth: true
                model: [
                    { text: "红色", color: "#e74c3c" },
                    { text: "蓝色", color: "#3498db" },
                    { text: "绿色", color: "#2ecc71" },
                    { text: "紫色", color: "#9b59b6" }
                ]
                textRole: "text"
                currentIndex: 0
            }


            Button {
                text: "应用"
                onClicked: {
                    if (loader.item) {
                        loader.item.displayText = textInput.text || "Hello"
                        loader.item.displayBgColor = colorPicker.model[colorPicker.currentIndex].color
                    }
                }
            }

            Button {
                text: "重置"
                onClicked: {
                    textInput.text = ""
                    colorPicker.currentIndex = 0
                    if (loader.item) {
                        loader.item.displayText = "Hello"
                        loader.item.displayBgColor = colorPicker.model[colorPicker.currentIndex].color
                    }
                }
            }
        }

        Rectangle {
            Layout.fillWidth: true
            Layout.fillHeight: true
            color: Qt.rgba(0.95, 0.95, 0.95, 1)
            radius: 4

            Loader {
                id: loader
                anchors.fill: parent
                anchors.margins: 10
                sourceComponent: displayComponent
                onLoaded: {
                    item.displayText = textInput.text || "Hello"
                    item.displayBgColor = colorPicker.model[colorPicker.currentIndex].color
                }
            }
        }
    }

    Component {
        id: displayComponent
        Rectangle {
            id: inner
            property string displayText: "Hello"
            property color displayBgColor: "#e74c3c"
            color: inner.displayBgColor
            radius: 6
            opacity: 0.9

            Text {
                anchors.centerIn: parent
                text: inner.displayText
                color: "#fff"
                font.pixelSize: 24
                font.bold: true
            }
        }
    }
}

代码说明

这个示例展示了 Loader 属性传递的完整工作流程。Loader 加载的 Component 内部声明了两个自定义属性 displayTextdisplayBgColor,外部通过 loader.item 访问并修改这些属性。

要点

  • 子组件必须使用 property 关键字声明可访问的属性
  • 通过 loader.item.propertyName 访问和修改属性
  • 访问 loader.item 前应先检查是否非空(if (loader.item)
  • 使用 onLoaded 信号可以在组件加载完成后初始化属性值

4. 技术要点

4.1 属性传递的三种方式

方式一:通过 onLoaded 信号初始化

Loader {
    id: loader
    sourceComponent: myComponent
    onLoaded: {
        item.displayText = "初始值"
        item.displayBgColor = "#ff0000"
    }
}

适用于组件加载后需要设置初始值的场景。

方式二:通过按钮事件动态修改

Button {
    text: "应用"
    onClicked: {
        if (loader.item) {
            loader.item.displayText = textInput.text
            loader.item.displayBgColor = "#3498db"
        }
    }
}

适用于用户交互触发属性变更的场景。

方式三:通过属性绑定实时更新

Loader {
    id: loader
    sourceComponent: myComponent
}

// 在其他地方绑定属性
Binding {
    target: loader.item
    property: "displayText"
    value: textInput.text
    when: loader.item !== null
}

适用于需要保持属性同步更新的场景。


4.2 子组件属性声明规范

Loader 加载的组件必须使用 property 关键字声明可外部访问的属性:

Component {
    id: myComponent
    Rectangle {
        id: inner
        
        // 声明可外部访问的属性
        property string displayText: "Hello"
        property color displayBgColor: "#e74c3c"
        property int displaySize: 24
        property bool isVisible: true
        
        // 使用这些属性
        color: inner.displayBgColor
        opacity: inner.isVisible ? 0.9 : 0

        Text {
            text: inner.displayText
            font.pixelSize: inner.displaySize
        }
    }
}

要点

  • 属性名应具有描述性,避免与内置属性冲突
  • 设置合理的默认值,确保组件在未设置属性时也能正常显示
  • 可以使用 property alias 创建属性别名,指向子对象的属性

4.3 安全访问 loader.item

由于 loader.item 在组件未加载时为 null,访问前必须进行检查:

// 错误:可能崩溃
loader.item.displayText = "Hello"

// 正确:先检查
if (loader.item) {
    loader.item.displayText = "Hello"
}

// 正确:使用可选链(部分 Qt 版本支持)
loader.item?.displayText = "Hello"

常见检查场景

  • 按钮点击事件中
  • 定时器回调中
  • 网络请求回调中
  • 任何可能先于组件加载完成的时机

4.4 ComboBox 数据模型与属性传递

本示例使用对象数组作为 ComboBox 的 model,通过 textRole 指定显示字段:

ComboBox {
    id: colorPicker
    model: [
        { text: "红色", color: "#e74c3c" },
        { text: "蓝色", color: "#3498db" },
        { text: "绿色", color: "#2ecc71" },
        { text: "紫色", color: "#9b59b6" }
    ]
    textRole: "text"
    currentIndex: 0
}

// 获取选中项的颜色
var selectedColor = colorPicker.model[colorPicker.currentIndex].color

要点

  • model 可以是数组、ListModel 或整数
  • textRole 指定显示文本对应的字段名
  • 通过 currentIndex 获取当前选中项索引
  • 对象数组模型可以存储多个字段,适用于复杂数据场景

4.5 TextField 输入处理

TextField {
    id: textInput
    placeholderText: "输入文字"
    maximumLength: 10
}

// 使用输入值(带默认值)
var text = textInput.text || "Hello"

要点

  • placeholderText 显示提示文本
  • maximumLength 限制输入长度
  • 使用 || 运算符提供默认值,当输入为空时使用默认文本

5. 常见问题

Q1:为什么修改属性后界面没有更新?

确保子组件的属性与 UI 元素正确绑定:

// 正确:属性与 UI 绑定
property color displayBgColor: "#e74c3c"
color: inner.displayBgColor  // 绑定到 color 属性

// 错误:只声明属性,没有绑定
property color displayBgColor: "#e74c3c"
color: "red"  // 固定值,不会随属性变化

Q2:如何在加载组件时自动应用当前设置?

使用 onLoaded 信号:

Loader {
    sourceComponent: displayComponent
    onLoaded: {
        item.displayText = textInput.text || "Hello"
        item.displayBgColor = colorPicker.model[colorPicker.currentIndex].color
    }
}

Q3:可以传递复杂对象作为属性吗?

可以,但需要注意属性类型声明:

property var dataModel: []
property var configObject: ({})
property var callback: null

Q4:属性传递和属性绑定有什么区别?

  • 属性传递:一次性赋值,后续不会自动同步
  • 属性绑定:使用 Binding 或表达式绑定,值变化时自动更新

6. 工程下载

下载链接:QML Loader 组件示例合集

在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐