QML 语法基础详解
目录
1. QML 文档结构
2. 对象与属性
3. 属性绑定 (Property Binding)
4. JavaScript in QML
示例代码:
1. QML 文档结构
一个 QML 文件(通常以 .qml
结尾)就是一个包含了 QML 对象树的文本文件。它有三个主要部分:
-
import
语句:-
位于文件的最顶端。
-
用于导入特定的模块或库,这些库提供了我们能使用的 QML 类型(如
Rectangle
,Text
等)。 -
例如
import QtQuick 2.15
就导入了 Qt Quick 模块的 2.15 版本,这是构建用户界面的基础。
-
-
对象树:
-
QML 界面是通过声明一个对象树来构建的。对象可以嵌套在其他对象中,形成父子关系。
-
这种层级关系不仅定义了视觉上的包含,也影响了属性(如坐标、尺寸)的继承和查找。
-
-
根元素:
-
每个 QML 文件 必须 只有一个根元素。所有的其他元素都必须是这个根元素的子孙。
-
这个根元素定义了该 QML 组件的“边界”。
-
2. 对象与属性
QML 的核心就是声明对象并配置它们的属性。
-
对象 (Object):
-
也称为“类型”或“元素”,比如
Item
,Rectangle
,Text
,Image
。 -
Item
是所有视觉元素中最基础的一个,它有x
,y
,width
,height
等基本属性,但本身不可见。 -
Rectangle
继承自Item
,并增加了color
,radius
等属性,使其可见。
-
-
属性 (Property):
-
每个对象都有一系列属性,用于控制其外观和行为。
-
语法是
propertyName: value
。 -
例如,
width: 200
将一个元素的宽度设置为 200 像素。text: "Hello, QML"
将一个Text
元素的显示内容设置为字符串 "Hello, QML"。
-
3. 属性绑定 (Property Binding)
这是 QML 最强大、最核心的特性。
-
什么是属性绑定?
-
属性绑定是一种声明式的关系,它让一个属性的值能够根据其他属性的值 自动更新。
-
一旦绑定建立,只要依赖的属性发生变化,被绑定的属性就会自动重新计算并应用新值。你 不需要 手动编写任何更新代码。
-
-
如何使用?
-
语法与普通赋值一样,
property: expression
。但当表达式中包含其他对象的属性时,绑定就自动创建了。 -
示例:
width: parent.width / 2
。这行代码的意思是:将当前元素的宽度 绑定 为其父元素宽度的一半。无论父元素的宽度如何变化(例如,窗口被用户拖拽调整大小),当前元素的宽度都会自动保持为父宽的一半。
-
-
响应式原理:
-
QML 引擎在后台构建了一个依赖关系图。当它发现
parent.width
改变时,就会自动通知所有依赖它的绑定,并触发它们重新计算。这就是 QML 的“响应式”编程模型。
-
4. JavaScript in QML
虽然属性绑定可以处理大部分 UI 逻辑,但有时我们仍然需要执行一些命令式的、复杂的逻辑。这时就可以在 QML 中嵌入 JavaScript。
-
使用场景:
-
信号处理器 (Signal Handlers): 当某个事件发生时(如点击),执行一段 JS 代码。信号处理器的命名规则是
on<SignalName>
,例如onClicked
。 -
自定义函数: 你可以在 QML 对象中定义自己的函数,以便在多个地方复用逻辑。
-
-
语法:
-
信号处理器:
MouseArea {onClicked: {// 这是一个 JS 代码块console.log("被点击了!");myFunction(someValue);} }
-
自定义函数:
Item {function myFunction(value) {// 这是一个 JS 函数return value * 2;} }
-
-
最佳实践:
-
优先使用属性绑定。只有当逻辑无法用绑定表达时(例如,响应一次性事件、执行复杂的计算或调用 C++ 函数),才使用 JavaScript。过度使用 JS 会破坏 QML 的声明式特性,并可能导致性能问题。
-
示例代码:
// 1. QML 文档结构: import 语句
// 导入 QtQuick 模块,这是基础
import QtQuick 2.15
// *** 修正 ***
// 导入 QtQuick.Window 模块,以使用 Window
import QtQuick.Window 2.15// 1. QML 文档结构: 根元素
// *** 修正 ***
// 使用 Window 作为根元素,它是一个更基础的窗口类型
Window {id: rootwidth: 400height: 300visible: truetitle: "QML 语法基础示例 (使用 Window)" // 设置窗口标题// 因为 Window 本身是透明的,我们添加一个 Rectangle 作为背景Rectangle {anchors.fill: parentcolor: "#f0f0f0"}// 自定义一个属性,用于在 JS 中改变它property bool isHello: true// 2. 对象与属性: Text 对象// 用于显示标题Text {id: titleTexttext: "QML 语法基础示例"font.bold: truefont.pixelSize: 20// 3. 属性绑定: 使用 anchors 进行布局// 将标题文本水平居中于父元素(root 窗口)anchors.horizontalCenter: parent.horizontalCenteranchors.top: parent.topanchors.topMargin: 10}// 2. 对象与属性: Rectangle 对象 (作为容器)Rectangle {id: contentBoxwidth: 300height: 150color: "#ffffff"border.color: "#cccccc"radius: 8// 3. 属性绑定: 使其在父元素(root 窗口)中居中anchors.centerIn: parent// 内部包含一个 Text 和一个 MouseAreaText {id: statusText// 3. 属性绑定: 文本内容依赖于根元素的 isHello 属性text: root.isHello ? "你好, QML!" : "再见, QML!"anchors.centerIn: parentfont.pixelSize: 18}// 2. 对象与属性: MouseArea 对象// 这是一个不可见的元素,用于处理鼠标事件MouseArea {// 将 MouseArea 的大小和其父元素 contentBox 绑定anchors.fill: parentcursorShape: Qt.PointingHandCursor // 鼠标悬停时显示手型// 4. JavaScript in QML: 信号处理器// 当点击事件发生时,执行这里的 JS 代码块onClicked: {console.log("方块被点击了!");// 调用下面定义的 JS 函数toggleStatus();}}}// 4. JavaScript in QML: 自定义函数// 在根元素中定义一个 JS 函数function toggleStatus() {console.log("执行 toggleStatus() 函数");// 改变自定义属性 isHello 的值// 注意: statusText 的 text 属性会因为绑定而自动更新!root.isHello = !root.isHello}
}