当前位置: 首页 > news >正文

QML自定义组件

自定义组件是 QML 开发中的核心概念,它允许您创建可重用的 UI 元素和逻辑单元。以下是创建和使用自定义组件的完整方法。

1. 基本自定义组件创建

创建单独组件文件 (推荐方式)

qml

// MyButton.qml(单独一个qml文件)
import QtQuick 2.15

Rectangle {
    id: root
    
    // 可自定义属性
    property string text: "Button"
    property color textColor: "white"
    signal clicked
    
    width: 120; height: 40
    color: mouseArea.containsMouse ? "#3498db" : "#2980b9"
    radius: 5
    
    Text {
        anchors.centerIn: parent
        text: root.text
        color: root.textColor
    }
    
    MouseArea {
        id: mouseArea
        anchors.fill: parent
        hoverEnabled: true
        onClicked: root.clicked()
    }
}

内联组件 (适用于简单组件)

qml

Item {
    component InlineButton: Rectangle {
        property string text
        width: 100; height: 30
        color: "lightgray"
        Text { anchors.centerIn: parent; text: parent.text }
    }

    InlineButton { text: "OK" }
    InlineButton { text: "Cancel" }
}

2. 组件属性与接口

定义属性

qml

// SmartInput.qml
Item {
    id: root
    
    // 基本属性
    property string placeholder: ""
    property string text: ""
    
    // 带默认值的属性
    property int maxLength: 100
    property bool isValid: text.length <= maxLength
    
    // 只读属性
    readonly property bool hasText: text.length > 0
    
    // 别名属性
    property alias cursorPosition: input.cursorPosition
    
    // 信号
    signal accepted(string text)
    signal validationChanged(bool valid)
    
    // 子元素
    TextInput {
        id: input
        anchors.fill: parent
        text: root.text
        onTextChanged: {
            root.text = text
            root.validationChanged(root.isValid)
        }
        onAccepted: root.accepted(text)
    }
}

使用属性

qml

SmartInput {
    id: myInput
    width: 200; height: 30
    placeholder: "请输入用户名"
    maxLength: 20
    
    onAccepted: console.log("输入内容:", text)
    onValidationChanged: (valid) => {
        console.log("验证状态:", valid)
    }
}

3. 组件间通信

方法1: 信号与槽

qml

// ToggleSwitch.qml
Item {
    id: root
    signal toggled(bool on)
    
    property bool on: false
    
    MouseArea {
        anchors.fill: parent
        onClicked: {
            root.on = !root.on
            root.toggled(root.on)
        }
    }
}

// 使用
ToggleSwitch {
    onToggled: (isOn) => {
        console.log("开关状态:", isOn)
    }
}

方法2: 函数调用

qml

// Counter.qml
Item {
    id: root
    
    property int count: 0
    
    function increment() {
        count++
    }
    
    function decrement() {
        count--
    }
}

// 使用
Counter {
    id: myCounter
}

Button {
    text: "增加"
    onClicked: myCounter.increment()
}
 

4. 动态组件

动态创建

qml

Item {
    id: container
    width: 300; height: 300
    
    function createDynamicItem() {
        var component = Qt.createComponent("DynamicItem.qml")
        if (component.status === Component.Ready) {
            var obj = component.createObject(container, {
                "x": Math.random() * 250,
                "y": Math.random() * 250
            })
        }
    }
}

动态加载 (Loader)

qml

Item {
    width: 300; height: 300
    
    Loader {
        id: componentLoader
        anchors.fill: parent
        source: "DynamicComponent.qml"
    }
    
    Button {
        text: "重新加载"
        onClicked: {
            componentLoader.source = ""
            componentLoader.source = "DifferentComponent.qml"
        }
    }
}

5. 高级组件模式

带模型的组件

qml

// ListItem.qml
Rectangle {
    id: root
    width: ListView.view ? ListView.view.width : 100
    height: 50
    
    required property string name
    required property string description
    
    color: mouseArea.containsMouse ? "#f0f0f0" : "white"
    
    Column {
        anchors.fill: parent
        anchors.margins: 5
        
        Text { text: name; font.bold: true }
        Text { text: description; font.pixelSize: 10 }
    }
    
    MouseArea {
        id: mouseArea
        anchors.fill: parent
        hoverEnabled: true
    }
}

// 使用
ListView {
    width: 200; height: 300
    model: ListModel {
        ListElement { name: "项目1"; description: "描述1" }
        ListElement { name: "项目2"; description: "描述2" }
    }
    delegate: ListItem {}
}

主题化组件

qml

// ThemedButton.qml
Rectangle {
    id: root
    
    // 主题属性
    property color primaryColor: "#3498db"
    property color hoverColor: Qt.darker(primaryColor, 1.2)
    property color textColor: "white"
    
    property string text: "Button"
    signal clicked
    
    width: 120; height: 40
    radius: 5
    color: mouseArea.containsMouse ? hoverColor : primaryColor
    
    Text {
        anchors.centerIn: parent
        text: root.text
        color: root.textColor
    }
    
    MouseArea {
        id: mouseArea
        anchors.fill: parent
        hoverEnabled: true
        onClicked: root.clicked()
    }
}

6. 最佳实践

  1. 单一职责原则:每个组件应该只负责一个功能

  2. 明确接口:通过属性和信号定义清晰的组件接口

  3. 合理命名:使用描述性名称 (如 PrimaryButton 而非 MyButton)

  4. 文档注释:为组件添加注释说明用法

  5. 默认值合理:为属性设置合理的默认值

  6. 性能优化:避免在组件内部进行复杂计算

7. 实际案例:带图标的按钮

IconButton.qml
Item {
    id: root
    
    // 公共API
    property alias icon: iconImage.source
    property alias text: label.text
    property color color: "#3498db"
    property color hoverColor: Qt.darker(color, 1.2)
    signal clicked
    
    width: Math.max(iconImage.width + label.width + 20, 80)
    height: 40
    
    Rectangle {
        anchors.fill: parent
        radius: 4
        color: mouseArea.containsMouse ? root.hoverColor : root.color
        
        Row {
            anchors.centerIn: parent
            spacing: 8
            
            Image {
                id: iconImage
                sourceSize.width: 20
                sourceSize.height: 20
            }
            
            Text {
                id: label
                color: "white"
                font.pixelSize: 14
            }
        }
    }
    
    MouseArea {
        id: mouseArea
        anchors.fill: parent
        hoverEnabled: true
        onClicked: root.clicked()
    }
    
    // 组件行为
    Behavior on color {
        ColorAnimation { duration: 200 }
    }
}
另外qml文件中引用
// 使用示例
IconButton {
    icon: "qrc:/icons/save.png"
    text: "保存"
    onClicked: console.log("保存按钮点击")
}

相关文章:

  • opencv(C++)处理图像颜色
  • Spring事务系列 三
  • 项目合同从专家到小白
  • Java final关键字规范说明
  • Linux学习笔记——设备驱动
  • ‌UniApp 安卓打包完整步骤(小白向)
  • 前端面试宝典---创建对象的配置
  • android 下提示 SQLITECIPHER driver not loaded
  • 链式触发器
  • 如何使用Tomcat
  • Day 9
  • Node 处理 request 的过程中,都会更新哪些 metadata 和 property
  • 餐饮厨房开源监控安全系统的智能革命
  • 小刚说C语言刷题——第20讲 循环之嵌套循环
  • 【面经】兼顾频繁插入/删除和查询访问 非阻塞网络I/O模型 connect的阻塞性 `unique_ptr`的使用场景和析构机制
  • 20年AB1解码java
  • 【PyTorch项目实战】卷积(Convolution ) + 反卷积(Deconvolution)
  • 文章记单词 | 第27篇(六级)
  • WePY 框架:小程序开发的“Vue式”利器!!!
  • gogs私服对应SSH 协议配置