【QML 快速入门】 组件(Compontents)
一、简介
Component 是由 Qt 框架或开发者封装好的、只暴露了必要接口的 QML 类型,可以重复利用的元素。一个 Component 就像一个黑盒子,它通过属性、信号、函数和外部世界交互。
QML 主要提供两种不同的方法来创建组件:一个 Component 可以定义在独立的 qml 文件中(例如 MyButton.qml),也可以嵌入到 qml 文档中来定义。如果一个 Component 比较小且只在某个 qml 文档中使用或者一个 Component 从逻辑上看从属于某个 qml 文档,那就可以采用嵌入的方式来定义该 Component 。你也可以与 C++ 的嵌套类对比来理解。
-
Component 通常用来给一个 view 提供图形化组件,比如
ListView::delegate
属性就需要一个 Component 来指定如何显示列表的每一个项。 -
Component 不是 Item 的派生类,而是从 QQmlComponent 继承而来,虽然它通过自己的顶层 item 为其它的 view 提供可视化组件,但它本身是不可见元素。你可以这么理解:你定义的组件是一个新的类型,它必须被实例化以后才可能显示。而要实例化一个嵌入在 qml 文档中定义的组件,则可以通过 Loader。后面我们详细讲述使用 Loader 的例子,这里先按下不表。
让我们来看看这个例子,我们创建了一个包含文本和鼠标区域的矩形框。它类似于一个简单的按钮,我们的目标就是让它足够简单。
import QtQuick 2.0
Item {
id: root
width: 140
height: 120
// 自定义内联按钮
Rectangle {
id: button
x: 12; y: 12
width: 116; height: 26
color: "lightsteelblue"
border.color: "slategrey"
Text {
anchors.centerIn: parent
text: "Start"
}
MouseArea {
anchors.fill: parent
onClicked: {
status.text = "Button clicked!"
}
}
}
// 当按钮按下,改变文本的text
Text {
id: status
x: 12; y: 76
width: 116; height: 26
text: "waiting ..."
horizontalAlignment: Text.AlignHCenter
}
}
用户界面将会看起来像下面这样。上面是初始化的状态,下面是按钮点击后的效果。
我们的目标是提取这个按钮作为一个可重复使用的组件。我们可以简单的考虑一下我们的按钮会有的哪些 API(应用程序接口),你可以自己考虑一下你的按钮应该有些什么。下面是我考虑的结果:
- 我想要使用 text 属性来设置文本,然后实现我们自己的点击操作。
- 我也期望这个按钮有一个比较合适的初始化大小(例如 width:240)。
二、文件式定义组件
为了完成我们的目标,我先使用文件式定义组件的方法,创建了一个 MyButton.qml 文件,并且将我们的代码拷贝了进去。我们在根级添加一个属性导出方便使用者修改它。
我们在根级导出了文本和点击信号。通常我们命名根元素为 root 让引用更加方便。我们使用了 QML 的 alias(别名)的功能,它可以将内部嵌套的 QML 元素的属性导出到外面使用。有一点很重要,只有根级目录的属性才能够被其它文件的组件访问。
// MyButton.qml
import QtQuick 2.0
Rectangle {
id: root
// 导出按钮属性
property alias text: label.text
// 自定义点击信号
signal clicked
width: 116; height: 26
color: "lightsteelblue"
border.color: "slategrey"
Text {
id: label
anchors.centerIn: parent
text: "Start"
}
MouseArea {
anchors.fill: parent
onClicked: {
root.clicked()
}
}
}
使用我们新的 MyButton 元素只需要在我们的文件中简单的声明一下就可以了,之前的例子将会被简化。
// main.qml
import QtQuick 2.0
Item {
id: root
width: 140
height: 120
// 文件式自定义按钮
MyButton {
id: myButton
x: 12; y: 12
text: "Start"
// 绑定的是自定义的"clicked信号"
onClicked: {
status.text = "Button clicked!"
}
}
// 当按钮按下,改变文本的text
Text {
id: status
x: 12; y: 76
width: 116; height: 26
text: "waiting ..."
horizontalAlignment: Text.AlignHCenter
}
}
现在你可以在你的用户界面代码中随意的使用 MyButton{ ... } 来作为按钮了。不过一个真正的按钮将更加复杂,比如提供按键反馈或者添加一些装饰。
注意:
就个人而言,可以更进一步的使用基础元素对象(Item)作为根元素。这样可以防止用户改变我们设计的按钮的颜色(Rectangle 有 color 属性,而 Item 没有),并且可以提供出更多相关控制的API(应用程序接口)。
Item {
id: root
Rectangle {
anchors.fill parent
color: "lightsteelblue"
border.color: "slategrey"
}
...
}
使用这项方式可以很简单的创建一系列可重用的组件。
三、嵌入式定义组件
一个嵌入式 Component 必须使用 Loader 来显示,代码如下:
import QtQuick 2.0
Item {
id: root
width: 140
height: 200
// 嵌入式按钮组件
Component {
id: buttonComponent
Rectangle {
id: myButton
width: 116; height: 26
color: "lightsteelblue"
border.color: "slategrey"
// 导出按钮属性
property alias text: label.text
// 自定义点击信号
signal clicked
Text {
id: label
anchors.centerIn: parent
text: "Start"
}
MouseArea {
anchors.fill: parent
onClicked: {
myButton.clicked()
}
}
}
}
// Loader加载"嵌入式自定义按钮"
Loader{
id: loader
anchors.bottom: parent.bottom
anchors.bottomMargin: 4
anchors.horizontalCenter: parent.horizontalCenter
sourceComponent: buttonComponent
onLoaded:{
// item指向myButton
item.color = "green"
}
}
// target 指向嵌入式按钮组件的顶层item—Rectangle,所以可以直接响应它的clicked信号。
Connections {
target: loader.item;
onClicked:{
status.text = "Button clicked!"
}
}
// 当按钮按下,改变文本的text
Text {
id: status
x: 12; y: 76
width: 116; height: 26
text: "waiting ..."
horizontalAlignment: Text.AlignHCenter
}
}
定义一个 Component 与定义一个 QML 文档类似, Component 只能包含一个顶层 item ,而且在这个 item 之外不能定义任何数据,除了 id 。
参考:
《Qt Quick核心编程》第7章
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】