一、概述
在 QML 中,基本元素(Basic Elements) 是构建 UI 界面的核心组件。QML 采用声明式语法,通过这些元素定义界面结构、行为和交互。元素可以被分为可视化元素与非可视化元素。一个可视化元素(例如矩形框Rectangle)有着几何形状并且可以在屏幕上显示。一个非可视化元素(例如计时器Timer)提供了常用的功能,通常用于操作可视化元素。
二、常用基本元素
2.1 基础视觉元素(常用于布局和显示)
2.1.1 元素 Item 的介绍和使用
在 QML 中,Item 是最基础的可视元素之一,许多其他图形元素(如 Rectangle、Image、Text 等)都直接或间接继承自 Item。它本身不绘制任何内容,但可以用于组织、布局和管理子项。
基本介绍:
Item {
id: rootItem
width: 200
height: 100
}
- Item 代表一个矩形区域,它本身不可见。
- 可以包含子元素,是容器型组件。
- 具有基本的坐标属性(x, y, width, height,anchors 等)。
- 常用于组合多个组件或布局结构中。
常用属性:
常见用途:
用作容器,组织子元素
Item {
width: 300; height: 100
Rectangle {
width: 100; height: 100; color: "red"
}
Rectangle {
x: 120
width: 100; height: 100; color: "blue"
}
}
用于布局锚定
Item {
width: 200; height: 200
Rectangle {
width: 50; height: 50; color: "green"
anchors.centerIn: parent
}
}
示例演示:
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
width: 400
height: 300
visible: true
title: qsTr("Item 示例")
// Item 是一个无可视外观的容器
Item {
id: container
width: 300
height: 200
anchors.centerIn: parent
// 第一个子元素
Rectangle {
width: 100
height: 100
color: "lightblue"
x: 0
y: 0
}
// 第二个子元素
Rectangle {
width: 100
height: 100
color: "lightgreen"
x: 120
y: 50
}
}
}
效果如下:
2.1.2 元素 Rectangle 的介绍和使用
Rectangle 是 QML 中最常用的可视化元素之一,用于绘制一个矩形区域。它可以设置颜色、大小、圆角、边框、渐变、阴影等属性,常用于 UI 中的背景、按钮、面板等组件。
基本语法:
Rectangle {
width: 200
height: 100
color: "lightblue"
}
常用属性说明:
示例 1:简单矩形
Rectangle {
width: 150
height: 80
color: "orange"
}
示例 2:带边框和圆角
Rectangle {
width: 200
height: 100
color: "white"
radius: 10
border.color: "black"
border.width: 2
}
示例 3:渐变背景
Rectangle {
width: 200
height: 100
gradient: Gradient {
GradientStop { position: 0.0; color: "red" }
GradientStop { position: 1.0; color: "yellow" }
}
}
示例 4:响应点击
Rectangle {
width: 100
height: 100
color: "lightgray"
MouseArea {
anchors.fill: parent
onClicked: {
parent.color = "green"
}
}
}
2.1.3 元素 Image 的介绍和使用
Image 是 QML 中用于显示图像的元素。它继承自 Item,可以加载本地图片或网络图片,支持缩放、填充模式、异步加载、缓存等功能。
基本语法:
Image {
source: "my_picture.png"
width: 100
height: 100
}
常用属性:
fillMode 填充模式:
示例 1:加载本地图片
Image {
source: "qrc:/images/logo.png"
width: 100
height: 100
fillMode: Image.PreserveAspectFit
}
示例 2:加载网络图片
Image {
source: "https://example.com/image.jpg"
asynchronous: true
cache: true
width: 200
height: 150
}
示例 4:点击更换图片
Image {
id: dynamicImage
source: "img1.png"
width: 100
height: 100
MouseArea {
anchors.fill: parent
onClicked: {
dynamicImage.source = "img2.png"
}
}
}
2.1.4 元素 Text 的介绍和使用
在 QML 中,Text 元素用于显示一段文本,是最基本的文字展示组件,具有强大的排版和样式能力。
基本语法:
Text {
text: "Hello, QML!"
font.pixelSize: 20
color: "black"
}
常用属性:
wrapMode 换行模式:
示例一:显示带样式的文本
Text {
text: "欢迎使用 QML!"
color: "#1684DF"
font.pixelSize: 24
font.bold: true
anchors.centerIn: parent
}
示例二:多行文本 + 自动换行
Text {
text: "这是一段很长的文本,用于测试自动换行是否有效。"
width: 200
wrapMode: Text.Wrap
}
示例三:超出省略显示(elide)
Text {
text: "这是一个超出显示宽度的文本"
width: 150
elide: Text.ElideRight
}
示例四:HTML 文本支持
Text {
text: "<b>加粗</b> <i>斜体</i> <font color='red'>红色</font>"
textFormat: Text.RichText
}
示例五:点击文本实现交互
Text {
id: clickableText
text: "点击我"
color: "blue"
MouseArea {
anchors.fill: parent
onClicked: {
clickableText.text = "你点击了我!"
}
}
}
2.2 交互元素(用于接收用户操作)
2.2.1 元素 MouseArea 介绍和使用
在 QML 中,MouseArea 是一个 用于处理鼠标交互的基础元素,常用于响应点击、按下、释放、移动等事件。
基本语法:
MouseArea {
anchors.fill: parent // 鼠标区域覆盖整个父项
onClicked: {
console.log("鼠标被点击了")
}
}
常用属性说明:
常用信号(事件):
示例:点击改变颜色
Rectangle {
width: 200; height: 200
color: "lightblue"
MouseArea {
anchors.fill: parent
onClicked: {
parent.color = "lightgreen"
console.log("点击了矩形")
}
}
}
示例:悬停改变鼠标样式
Rectangle {
width: 100; height: 100; color: "lightgray"
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onEntered: console.log("鼠标进入区域")
onExited: console.log("鼠标离开区域")
}
}
示例:获取鼠标位置
MouseArea {
anchors.fill: parent
onPositionChanged: {
console.log("鼠标位置:", mouse.x, mouse.y)
}
}
2.2.2 元素 FocusScope 的介绍和使用
在 QML 中,FocusScope 是一个 专门用于组织焦点(Focus)管理的容器元素。当你在组件中有多个可以获取焦点的子项时,使用 FocusScope 可以更清晰地控制哪个子控件获取焦点,避免焦点混乱。FocusScope 继承自 Item,本身不会获得焦点,但它能确保它内部的某个元素获得焦点时,焦点不会被传递到 FocusScope 外部。
基本语法:
FocusScope {
Rectangle {
width: 200; height: 40; color: "lightblue"
TextInput {
id: input1
anchors.centerIn: parent
focus: true // 初始获得焦点
}
}
}
示例1:多个输入框
FocusScope {
width: 300; height: 100
Column {
spacing: 10
TextInput {
id: input1
width: 200; height: 30
placeholderText: "输入框 1"
focus: true
}
TextInput {
id: input2
width: 200; height: 30`在这里插入代码片`
placeholderText: "输入框 2"
}
}
}
说明:这个 FocusScope 确保焦点不会传递到它之外,而是在 input1 和 input2 内部管理。
示例2:在组件中封装 FocusScope
// MyInputField.qml
FocusScope {
width: 200; height: 40
Rectangle {
anchors.fill: parent
color: "white"; border.color: "gray"
TextInput {
id: input
anchors.fill: parent
anchors.margins: 4
focus: true
}
}
}
// main.qml
Column {
spacing: 20
MyInputField {}
MyInputField {}
}
说明:即使你复用了 MyInputField,FocusScope 也能确保每个组件内部焦点独立。
注意事项:
- 不能仅靠 focus: true 管理多个控件焦点,需要用 FocusScope 做容器。
- 使用 Keys.onPressed 等键盘事件时,焦点必须在某个 focus: true 的控件上。
- 一个组件内部只能有一个主动获取焦点的控件,多个控件都设置 focus: true 会导致焦点冲突。
2.2.3 元素 Keys 介绍和使用
在 QML 中,Keys 是一个 用于处理键盘事件的附加属性对象,可以附加到可获得焦点的元素(如 Item、TextInput、TextField 等)上,以响应键盘输入。
基本用途:
Item {
focus: true // 只有获得焦点的元素才能接收键盘事件
Keys.onPressed: {
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
console.log("回车键被按下")
event.accepted = true // 表示已处理该事件,阻止继续传播
}
}
}
常用信号:
常见按键常量(来自 Qt.Key_*):
示例:方向键控制方块移动
Rectangle {
width: 300; height: 300; color: "white"
Rectangle {
id: box
width: 50; height: 50; color: "blue"
x: 0; y: 0
focus: true
Keys.onPressed: {
const step = 10;
if (event.key === Qt.Key_Right) {
box.x += step;
} else if (event.key === Qt.Key_Left) {
box.x -= step;
} else if (event.key === Qt.Key_Up) {
box.y -= step;
} else if (event.key === Qt.Key_Down) {
box.y += step;
}
}
}
}
注意事项:
- 必须设置 focus: true 才能接收键盘事件
- 如果键盘事件被多个元素监听,优先处理具有焦点的元素
- event.accepted = true 表示事件已处理,防止冒泡
示例:Tab 键切换焦点
TextField {
id: input1
focus: true
Keys.onPressed: {
if (event.key === Qt.Key_Tab) {
input2.forceActiveFocus()
event.accepted = true
}
}
}
TextField {
id: input2
}
示例:监听组合键(如 Ctrl + S)
Keys.onPressed: {
if (event.key === Qt.Key_S && event.modifiers & Qt.ControlModifier) {
console.log("Ctrl+S 被按下")
event.accepted = true
}
}
2.3 布局元素(用于排版、排列)
2.3.1 元素 Row 的介绍和使用
在 QML 中,Row 是一个非常常用的 可视化布局元素,用于将子元素按水平方向依次排列。
基本语法:
Row {
spacing: 10 // 子元素之间的间距
Rectangle { width: 50; height: 50; color: "red" }
Rectangle { width: 50; height: 50; color: "green" }
Rectangle { width: 50; height: 50; color: "blue" }
}
常用属性:
示例1:简单的水平排列
Row {
anchors.centerIn: parent
spacing: 20
Rectangle { width: 80; height: 40; color: "lightblue" }
Rectangle { width: 80; height: 40; color: "lightgreen" }
Rectangle { width: 80; height: 40; color: "lightpink" }
}
示例2:嵌套使用(Row + Column)
Column {
spacing: 10
Text { text: "用户名:" }
Row {
spacing: 5
Text { text: "账号:" }
TextField { width: 150 }
}
Row {
spacing: 5
Text { text: "密码:" }
TextField { width: 150; echoMode: TextInput.Password }
}
}
示例3:设置排列方向为从右到左
Row {
layoutDirection: Qt.RightToLeft
spacing: 10
Rectangle { width: 60; height: 40; color: "orange" }
Rectangle { width: 60; height: 40; color: "yellow" }
Rectangle { width: 60; height: 40; color: "gray" }
}
特性说明:
- Row 是 自动计算自身大小 的容器,默认高度为最高子项的高度,宽度为所有子项宽度之和加 spacing。
- Row 不会自动换行。如果你需要换行布局,可以使用 Flow。
- 子项可以通过 Layout.alignment 等属性进一步对齐(但前提是搭配 RowLayout 使用,而非 Row)。
2.3.2 元素 Column 的介绍和使用
在 QML 中,Column 是一个 基础的布局容器元素,它会自动将子元素 按垂直方向(从上到下)依次排列,适合用于表单、列表、按钮组等竖向布局场景。
基本语法:
Column {
spacing: 10 // 子元素之间的间距
Rectangle { width: 100; height: 40; color: "lightblue" }
Rectangle { width: 100; height: 40; color: "lightgreen" }
Rectangle { width: 100; height: 40; color: "lightpink" }
}
常用属性:
示例:简单的垂直排列
Column {
anchors.centerIn: parent
spacing: 12
Button { text: "开始" }
Button { text: "暂停" }
Button { text: "退出" }
}
示例:表单布局(使用 Column 嵌 Row)
Column {
spacing: 10
anchors.centerIn: parent
Row {
spacing: 10
Text { text: "用户名:" }
TextField { width: 150 }
}
Row {
spacing: 10
Text { text: "密码:" }
TextField { width: 150; echoMode: TextInput.Password }
}
Button {
text: "登录"
anchors.horizontalCenter: parent.horizontalCenter
}
}
Column 的局限性:
- 不会自动适配父容器宽度:默认只包裹内容大小
- 无法设置子项的对齐方式:所有子项默认左对齐,不能设置右对齐或居中(需手动处理)
- 不支持 Layout.* 属性:想用自动填充、拉伸等特性时,应该用 ColumnLayout
2.3.3 元素 Grid 的介绍和使用
在 QML 中,Grid 是一个用于 网格布局 的容器,它会将子元素按照指定的 行列数量 自动排列,类似于 HTML 的表格或 Excel 表格的布局效果。
基本语法:
Grid {
rows: 2
columns: 3
spacing: 10 // 子项之间的间距
Rectangle { width: 60; height: 40; color: "red" }
Rectangle { width: 60; height: 40; color: "green" }
Rectangle { width: 60; height: 40; color: "blue" }
Rectangle { width: 60; height: 40; color: "orange" }
Rectangle { width: 60; height: 40; color: "yellow" }
Rectangle { width: 60; height: 40; color: "purple" }
}
上面例子中,Grid 设定了 2 行 3 列。子项会从左到右,从上到下依次填入。
最终布局如下(颜色代表每个矩形):
| red | green | blue |
| orange | yellow | purple |
常用属性:
注意:rows 和 columns 至少设置一个,否则 Grid 无法正常布局。
示例:固定列数,自适应行数
Grid {
columns: 3
columnSpacing: 8
rowSpacing: 8
Repeater {
model: 10
Rectangle {
width: 50; height: 50
color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1.0)
}
}
}
示例:制作按钮九宫格
Grid {
columns: 3
spacing: 6
Repeater {
model: 9
Button {
text: (index + 1).toString()
width: 80
height: 50
}
}
}
示例:Grid + Text + Image 布局(联系人)
Grid {
columns: 2
spacing: 10
Repeater {
model: 4
Rectangle {
width: 150; height: 60; color: "#e0e0e0"
Row {
anchors.fill: parent
anchors.margins: 8
spacing: 10
Image {
source: "avatar.png"
width: 40; height: 40
fillMode: Image.PreserveAspectFit
}
Column {
Text { text: "姓名:张三" }
Text { text: "电话:123456789" }
}
}
}
}
}
2.3.4 元素 Flow 的介绍和使用
在 QML 中,Flow 是一个布局容器,它会将子元素从 左到右水平排列,当一行排满时,自动换行到下一行。适用于 标签云、图片展示、动态按钮列表等内容数量不定、宽度可能变化的场景。
基本用法:
Flow {
width: 300
spacing: 10
Rectangle { width: 80; height: 40; color: "lightblue" }
Rectangle { width: 100; height: 40; color: "lightgreen" }
Rectangle { width: 120; height: 40; color: "lightpink" }
Rectangle { width: 60; height: 40; color: "orange" }
Rectangle { width: 90; height: 40; color: "yellow" }
}
效果说明:
- 子项先在当前行从左到右排布
- 若子项宽度之和超过 Flow 宽度,会自动换到下一行
- 支持动态子项数量和大小,非常适合适配宽度变化
常用属性:
示例:标签自动换行展示
Flow {
width: 300
spacing: 8
Repeater {
model: ["C++", "Python", "JavaScript", "Rust", "Go", "Qt", "QML", "OpenCV"]
Rectangle {
height: 30
width: textItem.width + 20
color: "#d0e8ff"
radius: 4
Text {
id: textItem
anchors.centerIn: parent
text: modelData
font.pixelSize: 14
}
}
}
}
示例:方向从上往下排列(flow: TopToBottom)
Flow {
width: 300
height: 300
spacing: 5
flow: Flow.TopToBottom
Repeater {
model: 10
Rectangle {
width: 80; height: 40
color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
}
}
}
示例:按钮列表(自动换行)
Flow {
width: 320
spacing: 10
Repeater {
model: 15
Button {
text: "按钮" + index
}
}
}
特点总结:
2.3.5 元素 StackLayout 的介绍和使用
在 QML 中,StackLayout 是一个用于 堆叠多个子项并一次只显示一个 的布局容器。它非常适合做 页面切换、多步表单、标签页内容切换 等场景。
基本概念:
- StackLayout 将子项叠放在一起(Z 方向),只显示当前索引对应的一个子项。
- 通过修改其 currentIndex 属性来切换显示的子项。
最简用法示例:
import QtQuick 2.12
import QtQuick.Controls 2.12
ApplicationWindow {
visible: true
width: 400
height: 300
title: "StackLayout 示例"
Column {
spacing: 10
anchors.centerIn: parent
// 页面切换按钮
Row {
spacing: 10
Button { text: "页面 1"; onClicked: stack.currentIndex = 0 }
Button { text: "页面 2"; onClicked: stack.currentIndex = 1 }
Button { text: "页面 3"; onClicked: stack.currentIndex = 2 }
}
// StackLayout 布局:只显示当前索引的项
StackLayout {
id: stack
width: 300
height: 200
Rectangle {
color: "lightblue"
anchors.fill: parent
Text { text: "第一页"; anchors.centerIn: parent }
}
Rectangle {
color: "lightgreen"
anchors.fill: parent
Text { text: "第二页"; anchors.centerIn: parent }
}
Rectangle {
color: "lightpink"
anchors.fill: parent
Text { text: "第三页"; anchors.centerIn: parent }
}
}
}
}
结合 Repeater + StackLayout 实现动态内容:
property int pageCount: 5
StackLayout {
id: stack
currentIndex: 0
width: 300; height: 200
Repeater {
model: pageCount
Rectangle {
color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
anchors.fill: parent
Text {
anchors.centerIn: parent
text: "页面 " + (index + 1)
font.pixelSize: 20
}
}
}
}
常用属性和信号:
2.3.6 元素 StackView 的介绍和使用
在 QML 中,StackView 是一个强大的页面管理组件,它维护一个页面堆栈,支持页面的 push(进入)、pop(返回) 和 replace(替换) 操作,且带有默认的页面切换动画。
非常适合用来实现:
- 多页面导航(如设置页、详情页)
- 向前/向后导航操作
- 嵌套导航结构
基本结构示例:
import QtQuick 2.12
import QtQuick.Controls 2.12
ApplicationWindow {
visible: true
width: 400
height: 300
title: "StackView 示例"
StackView {
id: stackView
anchors.fill: parent
initialItem: Page1 {}
}
}
示例页面 Page1.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
Item {
width: 400; height: 300
Column {
anchors.centerIn: parent
spacing: 10
Text { text: "这是第一页" }
Button {
text: "跳转到第二页"
onClicked: stackView.push(Qt.resolvedUrl("Page2.qml"))
}
}
}
示例页面 Page2.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
Item {
width: 400; height: 300
Column {
anchors.centerIn: parent
spacing: 10
Text { text: "这是第二页" }
Button {
text: "返回上一页"
onClicked: stackView.pop()
}
}
}
常用操作:
属性与信号:
与 StackLayout 对比: