10.qml-组件、Loader、Component介绍
阅读原文时间:2023年07月08日阅读:2

1.组件介绍

  • 一个组件通常由一个qml文件定义(单独文件定义组件), 实际也可以在qml里面通过Component对象来嵌入式定义组件 (4小节讲解).
  • Component对象封装的内容默认不会显示,除非被加载后才可能显示, 并且是可以重复加载和移除的.
  • Component一般用来封装比较小,且需要重用的组件.

比如我们需要4个自定义按钮,我们只需要按钮颜色不同而已,此时就可以只需要定义一个按钮组件(Component),然后我们重复加载即可.而不是不停复制和粘贴来定义4个不同颜色的椭圆按钮.

2.单独文件定义组件

一个组件通常由一个qml文件定义,那么该文件名就是该组件的名字(类似于java,类名就是文件名).并且文件名最好是大驼峰格式.

由于我们是单独文件定义一个组件,所以不需要Component对象封装,并且创建好,我们就可以像使用qml其它元素一样来使用我们定义的组件.

首先我们创建一个名为DynamicBtn的自定义按钮组件:

DynamicBtn.qml内容如下所示:

import QtQuick 2.7
import QtQuick.Controls 2.0

Button {
id: btn
property var backColor: "#7BCBEB" // 背景颜色
property var fontPixelSize: 20 // 字体大小
property var fontColor: "#FFFFFF"

text: "button"  
implicitWidth: 100  
implicitHeight: 30  
hoverEnabled: true  
contentItem: Label {                    // 设置文本  
    id: btnForeground  
    text: parent.text  
    font.family: "Microsoft Yahei"  
    font.pixelSize: fontPixelSize  
    color: fontColor  
    horizontalAlignment: Text.AlignHCenter  
    verticalAlignment: Text.AlignVCenter  
    elide: Text.ElideRight  
}  
background: Rectangle {       // 绘制高亮范围  
    id: btnBack  
    color: backColor  
    radius: 6  
    Rectangle {  
        width: btnBack.width \* 0.9  
        height: btnBack.height \* 0.4  
        x:  btnBack.width \* 0.05  
        y:  btnBack.height \* 0.05  
        radius: 3  
        color:  Qt.lighter(btnBack.color, 1.19)

    }  
}  
onDownChanged: {  
    btnBack.color = down ? Qt.lighter(backColor, 0.9) : backColor // 设置按下的背景颜色  
}  
onHoveredChanged: {  
    btnBack.color = hovered ? Qt.lighter(backColor, 1.2) : backColor // 设置徘徊的背景颜色  
}  

}

然后我们在main.qml中就可以直接使用这个DynamicBtn组件了,就像使用qml内置的Window组件那样

main.qml内容如下所示:

Window{
visible: true
function onConfirmBtnClicked() {
console.log("你点击了确认按钮");
}
function onCancelBtnClicked() {
console.log("你点击了取消按钮");
}

Column {  
    spacing: 20  
    padding: 20  
    DynamicBtn {  
        id: confirmBtn  
        text: "确认"  
        backColor: "#5CA1F6"

    }  
    DynamicBtn {  
        id: cancelBtn  
        text: "取消"  
        backColor: "#FB6E62"  
    }  
    Component.onCompleted: {  
       confirmBtn.clicked.connect(onConfirmBtnClicked)  
       cancelBtn.clicked.connect(onCancelBtnClicked)  
    }  
}  

}

运行效果如下所示:

3.使用Loader对象动态加载和移除

在上节中,我们是在main.qml中直接使用这个DynamicBtn组件来静态显示,如果要动态加载和移除组件的话,则需要使用Loader对象,比如需要延时时间来显示对象之类的,都可以用Loader来实现.

Loader对象的属性如下所示:

  • active : bool,默认为true,表示Loader是激活的,如果设置为false,那么加载的视图项将会被释放,但是不会影响source或 sourceComponent里的内容.
  • asynchronous : bool,此属性保存组件是否将异步实例化,默认为false,在多个帧中创建组件声明的对象时,使用异步加载就可以降低动画中出现故障的可能性
  • item : object,此属性保存当前加载的顶级对象。
  • progress : real,此属性保存从网络加载QML数据的进度,从0.0(未加载)到1.0(完成)。大多数QML文件都很小,因此该值将迅速从0更改为1。
  • source : url,此属性保存要实例化的QML组件的URL。要卸载当前加载的对象,请将此属性设置为空字符串,将source设置为新URL也将导致卸载由先前URL创建的项。
  • sourceComponent : Component,此属性保存要实例化的Component,要卸载当前加载的对象,请将此属性设置为undefined
  • status : enumeration,保存当前加载的状态,分别有
  1. Loader.Null - the loader is inactive or no QML source has been set
  2. Loader.Ready - the QML source has been loaded
  3. Loader.Loading - the QML source is currently being loaded
  4. Loader.Error - an error occurred while loading the QML source

Loader的信号如下所示:

  • loaded() : 当status属性变为Loader.Ready成功加载后,会发出此信号。

我们还是以DynamicBtn组件为例,示例如下所示:

Window{
visible: true

function onLoad() {  
    loader1.source = "qrc:/DynamicBtn.qml"  
    loader2.source = "qrc:/DynamicBtn.qml"  
}  
function onRemove() {  
    loader1.source = ""  
    loader2.source = ""  
}  
function onConfirmBtnClicked() {  
    console.log("你点击了确认按钮");  
    btnText.text = "你点击了确认按钮"  
}  
function onCancelBtnClicked() {  
    console.log("你点击了取消按钮");  
    btnText.text = "你点击了取消按钮"  
}

Row {  
    id: row  
    spacing: 20  
    padding: 20  
    Button {  
        id: load  
        text: "加载"  
        onClicked: onLoad();  
    }  
    Button {  
        id: remove  
        text: "移除"  
        onClicked: onRemove();  
    }  
}

Column {  
    anchors.top: row.bottom  
    spacing: 20  
    padding: 20  
    Loader {  
        id: loader1  
        onLoaded: {  
            item.text = "确认"  
            item.backColor = "#5CA1F6"  
            item.clicked.connect(onConfirmBtnClicked)  
        }  
    }  
    Loader {  
        id: loader2  
        onLoaded: {  
            item.text = "取消"  
            item.backColor = "#FB6E62"  
            item.clicked.connect(onCancelBtnClicked)  
        }  
    }

    Text {  
        id: btnText  
        text: "等待按钮点击"  
    }  
}  

}

界面运行起来如下所示:

点击加载按钮后如下所示:

点击移除后,那么确认和取消按钮将会消失

4. 使用Component嵌入式定义组件

如果我们不想让自定义的按钮组件单独存在一个独立文件中,而是和main.qml一起的话,则需要用Component对象来封装它,修饰该对象是个组件对象.

并且Component只能包含一个顶层item,在这个item之外除了定义id外,不能定义其它任何属性.

然后我们在Loader的sourceComponent属性填入我们要加载的Component的id,即可加载显示.

Qt帮助示例如下所示:

import QtQuick 2.0

Item {
width: 100; height: 100

Component {
id: redSquare // Component里面只有一个id和一个顶层item,这里的顶层item是一个Rectangle矩形
Rectangle {
color: "red"
width: 10
height: 10
}
}
Loader { sourceComponent: redSquare } // 加载一个矩形
Loader { sourceComponent: redSquare; x: 20 } // 在x为20的位置处再次加载一个矩形
}

我们还是以DynamicBtn组件为例,来实现一个Component,示例如下所示:

import QtQuick 2.14
import QtQuick.Window 2.0
import QtQuick.Controls 2.0

Window{
visible: true

function onLoad() {  
    loader1.sourceComponent = dynamicBtn  
    loader2.sourceComponent = dynamicBtn  
}  
function onRemove() {  
    loader1.source = undefined  
    loader2.source = undefined  
}  
function onConfirmBtnClicked() {  
    console.log("你点击了确认按钮");  
    btnText.text = "你点击了确认按钮"  
}  
function onCancelBtnClicked() {  
    console.log("你点击了取消按钮");  
    btnText.text = "你点击了取消按钮"  
}

Row {  
    id: row  
    spacing: 20  
    padding: 20  
    Button {  
        id: load  
        text: "加载"  
        onClicked: onLoad();  
    }  
    Button {  
        id: remove  
        text: "移除"  
        onClicked: onRemove();  
    }

}

Column {  
    anchors.top: row.bottom  
    spacing: 20  
    padding: 20  
    Loader {  
        id: loader1  
        onLoaded: {  
            item.text = "确认"  
            item.backColor = "#5CA1F6"  
            item.clicked.connect(onConfirmBtnClicked)  
        }

    }  
    Loader {  
        id: loader2  
        onLoaded: {  
            item.text = "取消"  
            item.backColor = "#FB6E62"  
            item.clicked.connect(onCancelBtnClicked)  
        }  
    }

    Text {  
        id: btnText  
        text: "等待按钮点击"

    }  
}

Component {  
    id: dynamicBtn  
    Button {  
        property var backColor: "#7BCBEB"       // 背景颜色  
        text: "button"  
        implicitWidth: 100  
        implicitHeight: 32  
        hoverEnabled: true  
        contentItem: Label {                    // 设置文本  
            id: btnForeground  
            text: parent.text  
            font.family: "Microsoft Yahei"  
            font.pixelSize: 20  
            color: "#FFFFFF"  
            horizontalAlignment: Text.AlignHCenter  
            verticalAlignment: Text.AlignVCenter  
            elide: Text.ElideRight  
        }  
        background: Rectangle {  
            id: btnBack  
            color: backColor  
            radius: height / 4

            Rectangle {  
                width: btnBack.width \* 0.9  
                height: btnBack.height \* 0.4  
                x:  btnBack.width \* 0.05  
                y:  btnBack.height \* 0.05  
                radius: width / 2  
                color:  Qt.lighter(btnBack.color, 1.09)

            }  
        }  
        onDownChanged: {  
            btnBack.color = down ? Qt.lighter(backColor, 0.9) : backColor // 设置按下的背景颜色  
        }  
        onHoveredChanged: {  
            btnBack.color = hovered ? Qt.lighter(backColor, 1.1) : backColor // 设置徘徊的背景颜色  
        }  
    }  
}  

}

未完,下章学习组件其它动态创建方式:11.qml-通过方法来加载组件、字符串方式加载组件

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器