Qt Quick 学习笔记:枚举、数据类型、JavaScript 与自定义组件

Qt Quick 学习笔记:枚举、数据类型、JavaScript 与自定义组件

  • [Qt Quick 学习笔记:枚举、数据类型、JavaScript 与自定义组件](#Qt Quick 学习笔记:枚举、数据类型、JavaScript 与自定义组件)
  • [二、枚举 Enumeration](#二、枚举 Enumeration)
    • [2.1 什么是枚举](#2.1 什么是枚举)
    • [2.2 枚举的命名规则](#2.2 枚举的命名规则)
    • [2.3 定义枚举](#2.3 定义枚举)
    • [2.4 使用枚举](#2.4 使用枚举)
    • [2.5 手动指定枚举值](#2.5 手动指定枚举值)
    • [2.6 枚举适合什么场景](#2.6 枚举适合什么场景)
  • [三、QML 基本类型](#三、QML 基本类型)
    • [3.1 使用 property 声明属性](#3.1 使用 property 声明属性)
    • [3.2 int 整数类型](#3.2 int 整数类型)
    • [3.3 bool 布尔类型](#3.3 bool 布尔类型)
    • [3.4 real 浮点类型](#3.4 real 浮点类型)
    • [3.5 string 字符串类型](#3.5 string 字符串类型)
    • [3.6 url 类型](#3.6 url 类型)
    • [3.7 var 通用类型](#3.7 var 通用类型)
    • [3.8 常用基本类型总结](#3.8 常用基本类型总结)
  • [四、QtQuick 中的常用类型](#四、QtQuick 中的常用类型)
    • [4.1 color 颜色类型](#4.1 color 颜色类型)
    • [4.2 font 字体类型](#4.2 font 字体类型)
    • [4.3 point 坐标类型](#4.3 point 坐标类型)
    • [4.4 size 尺寸类型](#4.4 size 尺寸类型)
    • [4.5 rect 矩形类型](#4.5 rect 矩形类型)
    • [4.6 其他类型](#4.6 其他类型)
  • 五、对象类型
    • [5.1 基本类型和对象类型的区别](#5.1 基本类型和对象类型的区别)
  • [六、JavaScript 类型](#六、JavaScript 类型)
    • [6.1 JavaScript 数组](#6.1 JavaScript 数组)
    • [6.2 JavaScript 对象](#6.2 JavaScript 对象)
    • [6.3 JavaScript 日期](#6.3 JavaScript 日期)
  • [七、JavaScript 在 QML 中的定位](#七、JavaScript 在 QML 中的定位)
    • [7.1 QML 与 JavaScript 的关系](#7.1 QML 与 JavaScript 的关系)
  • [八、JavaScript 属性绑定](#八、JavaScript 属性绑定)
    • [8.1 绑定固定值](#8.1 绑定固定值)
    • [8.2 绑定表达式](#8.2 绑定表达式)
    • [8.3 绑定其他对象属性](#8.3 绑定其他对象属性)
    • [8.4 绑定 JavaScript 函数](#8.4 绑定 JavaScript 函数)
    • [8.5 直接赋值会解除原绑定](#8.5 直接赋值会解除原绑定)
  • [九、自定义 JavaScript 函数](#九、自定义 JavaScript 函数)
    • [9.1 无参数函数](#9.1 无参数函数)
    • [9.2 带参数函数](#9.2 带参数函数)
    • [9.3 计数器示例](#9.3 计数器示例)
    • [9.4 复杂判断建议封装成函数](#9.4 复杂判断建议封装成函数)
  • [十、导入外部 JavaScript 文件](#十、导入外部 JavaScript 文件)
  • [十一、自定义 QML 组件](#十一、自定义 QML 组件)
    • [11.1 为什么需要自定义组件](#11.1 为什么需要自定义组件)
    • [11.2 自定义组件命名规则](#11.2 自定义组件命名规则)
    • [11.3 创建简单自定义组件](#11.3 创建简单自定义组件)
    • [11.4 使用自定义组件](#11.4 使用自定义组件)
    • [11.5 自定义组件的作用](#11.5 自定义组件的作用)
  • [十二、QML 作用域](#十二、QML 作用域)
    • [12.1 parent 的作用](#12.1 parent 的作用)
    • [12.2 嵌套对象中的 parent](#12.2 嵌套对象中的 parent)
    • [12.3 使用 id 明确访问对象](#12.3 使用 id 明确访问对象)
  • [十三、QML 代码风格](#十三、QML 代码风格)
    • [13.1 推荐的对象声明顺序](#13.1 推荐的对象声明顺序)
    • [13.2 属性组写法](#13.2 属性组写法)
    • [13.3 anchors 属性组](#13.3 anchors 属性组)
    • [13.4 信号处理器的位置](#13.4 信号处理器的位置)
    • [13.5 保持统一比风格选择更重要](#13.5 保持统一比风格选择更重要)
  • 十四、综合示例
  • 十五、本节总结
  • 十六、快速复习表
  • 十七、一句话总结

Qt Quick 学习笔记:枚举、数据类型、JavaScript 与自定义组件

本篇整理 Qt Quick 开发中关于枚举、QML 数据类型、JavaScript、自定义组件、作用域以及代码风格的基础知识。

这些内容主要用于帮助我们进一步理解:QML 中的数据如何保存、界面逻辑如何处理,以及重复界面如何封装成组件。


一、本节内容概览

本文主要包含以下知识点:

  • QML 枚举的定义与使用
  • QML 常见基本类型
  • QtQuick 提供的常用类型
  • 对象类型与 JavaScript 类型
  • JavaScript 在 QML 中的定位
  • JavaScript 属性绑定
  • QML 自定义函数
  • 外部 JavaScript 文件导入
  • 自定义 QML 组件
  • QML 作用域
  • QML 代码风格

二、枚举 Enumeration

2.1 什么是枚举

枚举用于定义一组固定的、具有明确名称的选项。

例如,一个设备类型可能只有下面几种:

text 复制代码
手机
电脑
显示器
音箱

如果直接使用数字表示:

text 复制代码
0
1
2
3

代码的可读性会比较差。

使用枚举后,可以用有意义的名称表示这些状态:

text 复制代码
Smartphone
Computer
Screen
Speaker

枚举的关键字是:

qml 复制代码
enum

2.2 枚举的命名规则

在 QML 中定义枚举时,需要注意:

  1. 自定义 QML 文件名必须以大写字母开头;
  2. 枚举名称必须以大写字母开头;
  3. 枚举元素一般也使用大写字母开头;
  4. 文件名只能使用字母、数字和下划线等合法字符。

例如,可以创建一个文件:

text 复制代码
AppEnums.qml

不要使用:

text 复制代码
appEnums.qml
1Enums.qml
app-enums.qml

2.3 定义枚举

新建 AppEnums.qml

qml 复制代码
import QtQuick

QtObject {
    enum Fruit {
        Apple,
        Banana,
        Orange
    }
}

这里定义了一个名为 Fruit 的枚举。

其中包含:

text 复制代码
Apple
Banana
Orange

枚举的值默认从 0 开始,并依次递增:

text 复制代码
Apple  = 0
Banana = 1
Orange = 2

2.4 使用枚举

假设 AppEnums.qmlMain.qml 位于同一个目录,可以直接使用:

qml 复制代码
import QtQuick
import QtQuick.Controls

Window {
    width: 600
    height: 400
    visible: true

    property int currentFruit: AppEnums.Fruit.Apple

    Component.onCompleted: {
        console.log("Apple:", AppEnums.Fruit.Apple)
        console.log("Banana:", AppEnums.Fruit.Banana)
        console.log("Orange:", AppEnums.Fruit.Orange)
    }
}

输出结果类似:

text 复制代码
Apple:0
Banana:1
Orange:2

2.5 手动指定枚举值

枚举也可以手动指定起始值:

qml 复制代码
import QtQuick

QtObject {
    enum Device {
        Smartphone = 1024,
        Computer,
        Screen,
        Speaker
    }
}

后面的值会自动递增:

text 复制代码
Smartphone = 1024
Computer   = 1025
Screen     = 1026
Speaker    = 1027

使用:

qml 复制代码
Component.onCompleted: {
    console.log(AppEnums.Device.Smartphone)
    console.log(AppEnums.Device.Computer)
}

2.6 枚举适合什么场景

枚举适合表示一组固定状态,例如:

text 复制代码
设备类型
页面状态
用户权限
连接状态
学习阶段
主题模式

例如:

qml 复制代码
enum StudyState {
    Preview,
    Practice,
    Review
}

比直接使用:

qml 复制代码
property int studyState: 1

更加容易理解。


三、QML 基本类型

3.1 使用 property 声明属性

QML 中可以使用 property 声明自定义属性。

基本格式:

qml 复制代码
property 属性类型 属性名称: 初始值

例如:

qml 复制代码
property int count: 10
property bool running: true
property real ratio: 3.14
property string title: "Qt Quick"

3.2 int 整数类型

int 用于保存整数,包括:

  • 正整数
  • 负整数
  • 0

例如:

qml 复制代码
property int count: 100
property int offset: -20
property int defaultValue: 0

使用:

qml 复制代码
Component.onCompleted: {
    console.log(count)
    console.log(offset)
}

3.3 bool 布尔类型

bool 只有两个值:

qml 复制代码
true
false

例如:

qml 复制代码
property bool visibleState: true
property bool finished: false

可以用于条件判断:

qml 复制代码
Text {
    text: finished ? "已经完成" : "尚未完成"
}

为了提高可读性,也可以使用 if

qml 复制代码
Text {
    text: {
        if (finished) {
            return "已经完成"
        }

        return "尚未完成"
    }
}

3.4 real 浮点类型

real 用于保存小数。

例如:

qml 复制代码
property real ratio: 3.14
property real scaleValue: 1.5

使用:

qml 复制代码
Rectangle {
    width: 200 * scaleValue
    height: 100
}

3.5 string 字符串类型

string 用于保存文字。

例如:

qml 复制代码
property string userName: "Tom"
property string message: "欢迎学习 QML"

显示:

qml 复制代码
Text {
    text: message
}

字符串也可以拼接:

qml 复制代码
Text {
    text: "用户名:" + userName
}

3.6 url 类型

url 用于保存文件路径或网址。

例如:

qml 复制代码
property url imageSource: "images/logo.png"

使用:

qml 复制代码
Image {
    source: imageSource
}

3.7 var 通用类型

var 可以保存不同类型的数据。

例如:

qml 复制代码
property var numberValue: 100
property var textValue: "QML"
property var arrayValue: ["Qt", "QML", "C++"]

输出:

qml 复制代码
Component.onCompleted: {
    console.log(numberValue)
    console.log(textValue)
    console.log(arrayValue[0])
}

var 使用方便,但如果已经知道具体类型,建议优先写明确类型。

推荐:

qml 复制代码
property int count: 10

而不是:

qml 复制代码
property var count: 10

明确类型更方便阅读和检查错误。


3.8 常用基本类型总结

类型 用途 示例
int 整数 property int count: 10
bool 真或假 property bool running: true
real 小数 property real ratio: 1.5
string 字符串 property string name: "Tom"
url 路径或网址 property url source: "logo.png"
var 通用类型 property var data: []
list 对象列表 保存多个对象

四、QtQuick 中的常用类型

除了普通的 QML 基本类型,QtQuick 还提供了一些常用类型。


4.1 color 颜色类型

color 用于保存颜色。

qml 复制代码
property color themeColor: "lightgreen"

使用:

qml 复制代码
Rectangle {
    width: 300
    height: 200
    color: themeColor
}

颜色可以使用名称:

qml 复制代码
"red"
"blue"
"green"
"lightgray"

也可以使用十六进制:

qml 复制代码
"#ff0000"
"#00ff00"
"#336699"

4.2 font 字体类型

字体通常作为对象属性使用:

qml 复制代码
Text {
    text: "Qt Quick"

    font.pixelSize: 24
    font.bold: true
}

也可以使用属性组:

qml 复制代码
Text {
    text: "Qt Quick"

    font {
        pixelSize: 24
        bold: true
        italic: false
    }
}

两种写法效果相同。


4.3 point 坐标类型

point 保存一个二维坐标,包含:

text 复制代码
x
y

定义:

qml 复制代码
property point startPoint: Qt.point(100, 50)

访问:

qml 复制代码
Component.onCompleted: {
    console.log("x:", startPoint.x)
    console.log("y:", startPoint.y)
}

4.4 size 尺寸类型

size 保存宽度和高度:

text 复制代码
width
height

定义:

qml 复制代码
property size panelSize: Qt.size(300, 200)

访问:

qml 复制代码
Component.onCompleted: {
    console.log(panelSize.width)
    console.log(panelSize.height)
}

4.5 rect 矩形类型

rect 同时保存:

text 复制代码
x
y
width
height

定义:

qml 复制代码
property rect panelRect: Qt.rect(20, 30, 300, 200)

访问:

qml 复制代码
Component.onCompleted: {
    console.log(panelRect.x)
    console.log(panelRect.y)
    console.log(panelRect.width)
    console.log(panelRect.height)
}

4.6 其他类型

QtQuick 中还包括:

  • date
  • vector2d
  • vector3d
  • matrix4x4
  • quaternion

这些类型通常用于:

  • 日期处理
  • 二维或三维坐标
  • 图像变换
  • 3D 场景
  • 旋转和矩阵运算

初学阶段先知道它们的用途即可,实际用到时可以通过 Qt Creator 的帮助文档查询。


五、对象类型

基本类型用于保存数据,而对象类型可以创建具体对象。

例如:

qml 复制代码
Rectangle {
}

Button {
}

Text {
}

这些都是对象类型。


5.1 基本类型和对象类型的区别

基本类型:

qml 复制代码
property int count: 10
property string title: "QML"

对象类型:

qml 复制代码
Rectangle {
    width: 200
    height: 100
}

可以简单理解为:

text 复制代码
基本类型:保存一个值
对象类型:创建一个具有多个属性和功能的对象

例如,Rectangle 中可以同时包含:

qml 复制代码
Rectangle {
    width: 200
    height: 100
    color: "red"
    radius: 10
}

六、JavaScript 类型

QML 中可以使用 JavaScript 的数组、对象和日期等类型。


6.1 JavaScript 数组

定义数组:

qml 复制代码
property var names: ["Tom", "Jack", "Lucy"]

访问:

qml 复制代码
Component.onCompleted: {
    console.log(names[0])
    console.log(names[1])
    console.log(names.length)
}

输出:

text 复制代码
Tom
Jack
3

修改数组:

qml 复制代码
Component.onCompleted: {
    names[0] = "Mike"

    console.log(names[0])
}

6.2 JavaScript 对象

定义对象:

qml 复制代码
property var student: {
    "name": "Tom",
    "score": 90
}

访问:

qml 复制代码
Component.onCompleted: {
    console.log(student.name)
    console.log(student.score)
}

6.3 JavaScript 日期

创建日期对象:

qml 复制代码
property var currentDate: new Date()

使用:

qml 复制代码
Component.onCompleted: {
    console.log("当前年份:", currentDate.getFullYear())
    console.log("当前月份:", currentDate.getMonth() + 1)
    console.log("当前日期:", currentDate.getDate())
}

需要注意:

qml 复制代码
getMonth()

返回值通常从 0 开始,因此显示自然月份时一般需要加 1


七、JavaScript 在 QML 中的定位

JavaScript 在 QML 中主要用于:

  • 实现简单界面逻辑;
  • 处理条件判断;
  • 编写函数;
  • 处理数组和对象;
  • 计算属性值;
  • 响应信号。

例如:

qml 复制代码
Button {
    text: "增加"

    onClicked: {
        count += 1
    }
}

这里的:

qml 复制代码
count += 1

就是 JavaScript 语句。


7.1 QML 与 JavaScript 的关系

可以简单理解为:

text 复制代码
QML:主要负责描述界面
JavaScript:辅助处理界面逻辑
C++:负责复杂业务逻辑和后端功能

JavaScript 不适合承担大量复杂业务逻辑。

如果 QML 文件中出现大量复杂判断和数据处理,代码会变得难以维护。


八、JavaScript 属性绑定

QML 属性可以绑定到:

  • 固定值;
  • 表达式;
  • 其他对象属性;
  • JavaScript 函数。

8.1 绑定固定值

qml 复制代码
width: 200

8.2 绑定表达式

qml 复制代码
width: parent.width / 2

8.3 绑定其他对象属性

qml 复制代码
Rectangle {
    id: redRectangle

    width: 200
    height: 100
    color: "red"
}

Rectangle {
    width: redRectangle.width / 2
    height: 100
    color: "blue"
}

红色矩形宽度改变时,蓝色矩形宽度会自动变化。


8.4 绑定 JavaScript 函数

qml 复制代码
Window {
    width: 600
    height: 400
    visible: true

    property int baseWidth: 100

    function calculateWidth() {
        return baseWidth * 2
    }

    Rectangle {
        width: calculateWidth()
        height: 100
        color: "lightblue"
    }
}

8.5 直接赋值会解除原绑定

假设:

qml 复制代码
Rectangle {
    id: blueRectangle

    width: redRectangle.width / 2
}

这里存在属性绑定。

如果后面写:

qml 复制代码
blueRectangle.width = 300

原来的绑定关系可能会被新的固定值替代。

之后即使:

qml 复制代码
redRectangle.width

发生变化,蓝色矩形也可能不会继续变化。

因此,应尽量修改被绑定的源属性:

qml 复制代码
redRectangle.width = 600

九、自定义 JavaScript 函数

9.1 无参数函数

qml 复制代码
function showMessage() {
    console.log("Hello QML")
}

调用:

qml 复制代码
showMessage()

9.2 带参数函数

qml 复制代码
function add(a, b) {
    return a + b
}

调用:

qml 复制代码
Component.onCompleted: {
    var result = add(10, 20)

    console.log(result)
}

9.3 计数器示例

qml 复制代码
import QtQuick
import QtQuick.Controls

Window {
    id: mainWindow

    width: 600
    height: 400
    visible: true

    property int count: 0

    Text {
        anchors.centerIn: parent

        text: "当前计数:" + mainWindow.count
        font.pixelSize: 28
    }

    Button {
        text: "+"

        anchors.left: parent.left
        anchors.bottom: parent.bottom
        anchors.leftMargin: 20
        anchors.bottomMargin: 20

        onClicked: {
            mainWindow.addCount()
        }
    }

    Button {
        text: "-"

        anchors.right: parent.right
        anchors.bottom: parent.bottom
        anchors.rightMargin: 20
        anchors.bottomMargin: 20

        onClicked: {
            mainWindow.reduceCount()
        }
    }

    function addCount() {
        if (count < 10) {
            count += 1
        }
    }

    function reduceCount() {
        if (count > 0) {
            count -= 1
        }
    }
}

9.4 复杂判断建议封装成函数

不推荐把复杂判断全部写进属性:

qml 复制代码
text: score >= 90 ? "优秀"
                  : score >= 60 ? "及格"
                                : "不及格"

更推荐使用函数:

qml 复制代码
Text {
    text: getScoreMessage()
}
qml 复制代码
function getScoreMessage() {
    if (score >= 90) {
        return "优秀"
    }

    if (score >= 60) {
        return "及格"
    }

    return "不及格"
}

这种写法更容易阅读和添加注释。


十、导入外部 JavaScript 文件

当 JavaScript 函数较多时,可以将它们放到单独的 .js 文件中。

例如,新建:

text 复制代码
MathTools.js

内容:

javascript 复制代码
function add(a, b) {
    return a + b
}

function subtract(a, b) {
    return a - b
}

在 QML 中导入:

qml 复制代码
import "MathTools.js" as MathTools

使用:

qml 复制代码
import QtQuick
import QtQuick.Controls
import "MathTools.js" as MathTools

Window {
    width: 600
    height: 400
    visible: true

    Component.onCompleted: {
        console.log(MathTools.add(10, 20))
        console.log(MathTools.subtract(20, 5))
    }
}

这里的:

qml 复制代码
MathTools

是导入 JavaScript 文件后使用的命名空间。


十一、自定义 QML 组件

11.1 为什么需要自定义组件

当一个界面结构需要重复使用时,可以将其封装成自定义组件。

例如:

  • 自定义按钮
  • 用户信息卡片
  • 计数器面板
  • 标题栏
  • 设置项
  • 状态提示框

这样可以减少重复代码。


11.2 自定义组件命名规则

自定义 QML 文件必须:

  1. 以大写字母开头;
  2. 只能使用字母、数字和下划线;
  3. 文件名会成为组件类型名。

正确示例:

text 复制代码
MyButton.qml
InfoCard.qml
CounterPanel.qml

错误示例:

text 复制代码
myButton.qml
1Button.qml
my-button.qml

11.3 创建简单自定义组件

新建:

text 复制代码
ColorCard.qml

内容:

qml 复制代码
import QtQuick

Rectangle {
    id: root

    property string title: "默认标题"
    property color innerColor: "lightblue"

    width: 300
    height: 200
    radius: 12
    color: "#eeeeee"

    Rectangle {
        width: 200
        height: 100
        color: root.innerColor

        anchors.centerIn: parent

        Text {
            anchors.centerIn: parent
            text: root.title
        }
    }
}

这里定义了两个对外可访问的属性:

qml 复制代码
property string title
property color innerColor

11.4 使用自定义组件

如果 ColorCard.qmlMain.qml 位于同一个目录,可以直接使用:

qml 复制代码
import QtQuick
import QtQuick.Controls

Window {
    width: 600
    height: 400
    visible: true

    ColorCard {
        anchors.centerIn: parent

        title: "QML 自定义组件"
        innerColor: "lightgreen"
    }
}

同一目录中的 QML 文件,一般不需要额外写目录导入。


11.5 自定义组件的作用

自定义组件可以实现:

  • 封装内部界面;
  • 对外提供简单属性;
  • 避免重复代码;
  • 提高复用性;
  • 让主页面代码更清晰。

外部不需要关心内部具体结构,只需要设置公开属性:

qml 复制代码
ColorCard {
    title: "欢迎"
    innerColor: "orange"
}

十二、QML 作用域

作用域决定:

  1. 当前表达式可以访问哪些变量;
  2. 当出现同名属性时,优先访问哪个;
  3. parent 指向哪个对象。

12.1 parent 的作用

parent 表示当前对象的直接父对象。

qml 复制代码
Window {
    width: 600
    height: 400

    Rectangle {
        width: parent.width / 2
        height: parent.height / 2
    }
}

这里 Rectangle 的父对象是 Window

所以:

qml 复制代码
parent.width

表示窗口宽度。


12.2 嵌套对象中的 parent

qml 复制代码
Window {
    width: 600
    height: 400

    Rectangle {
        width: 400
        height: 300

        Rectangle {
            width: parent.width / 2
            height: parent.height / 2
        }
    }
}

最内层矩形的:

qml 复制代码
parent

指向外层 Rectangle,不是 Window


12.3 使用 id 明确访问对象

当对象嵌套较多时,使用 id.属性 更清楚。

qml 复制代码
Window {
    id: mainWindow

    width: 600
    height: 400

    Rectangle {
        width: mainWindow.width / 2
        height: mainWindow.height / 2
    }
}

相比:

qml 复制代码
parent.width

下面这种写法更明确:

qml 复制代码
mainWindow.width

在作用域复杂时,推荐使用:

text 复制代码
对象 id + 点 + 属性名

例如:

qml 复制代码
mainWindow.width
messageText.text
contentRectangle.color

十三、QML 代码风格

代码风格不会改变程序的运行结果,但会影响:

  • 可读性
  • 可维护性
  • 团队协作
  • 后期修改
  • 代码移植

13.1 推荐的对象声明顺序

一个 QML 对象中,可以按照下面的顺序书写:

text 复制代码
1. id
2. 自定义属性
3. 自定义信号
4. JavaScript 函数
5. 对象自身属性
6. 子对象
7. 信号处理器

例如:

qml 复制代码
Rectangle {
    id: root

    property int count: 0
    property string title: "计数器"

    signal countUpdated(int value)

    function addCount() {
        count += 1
    }

    width: 300
    height: 200
    color: "lightblue"

    Text {
        anchors.centerIn: parent
        text: root.count
    }

    MouseArea {
        anchors.fill: parent

        onClicked: {
            root.addCount()
            root.countUpdated(root.count)
        }
    }

    onCountUpdated: function(value) {
        console.log("当前值:", value)
    }
}

13.2 属性组写法

单独写:

qml 复制代码
font.pixelSize: 24
font.bold: true
font.italic: false

属性组写法:

qml 复制代码
font {
    pixelSize: 24
    bold: true
    italic: false
}

属性较多时,使用属性组更加整齐。


13.3 anchors 属性组

可以单独写:

qml 复制代码
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.leftMargin: 20
anchors.bottomMargin: 20

也可以使用属性组:

qml 复制代码
anchors {
    left: parent.left
    bottom: parent.bottom
    leftMargin: 20
    bottomMargin: 20
}

两种方式效果相同。


13.4 信号处理器的位置

信号处理器可以放在对象内部合适的位置。

例如按钮:

qml 复制代码
Button {
    text: "点击"

    onPressed: {
        console.log("鼠标按下")
    }

    onReleased: {
        console.log("鼠标释放")
    }

    onClicked: {
        console.log("按钮点击完成")
    }
}

为了方便阅读,建议保持统一风格,例如统一放在对象属性后面。


13.5 保持统一比风格选择更重要

不同项目可能使用不同代码风格。

例如:

  • Qt 官方风格
  • 公司内部风格
  • 团队约定风格
  • 个人统一风格

代码风格没有绝对的唯一答案,但必须保持:

text 复制代码
统一
清晰
易读
易维护

十四、综合示例

下面使用本节学习的内容,编写一个简单的学习状态面板。

qml 复制代码
import QtQuick
import QtQuick.Controls

Window {
    id: mainWindow

    width: 700
    height: 450
    visible: true
    title: "QML 数据类型综合示例"

    enum StudyState {
        Preview,
        Practice,
        Review
    }

    property string studentName: "Tom"
    property int practiceCount: 0
    property real progressValue: practiceCount / 10.0
    property bool finished: practiceCount >= 10
    property color panelColor: finished
                               ? "lightgreen"
                               : "lightblue"

    property int currentState: StudyState.Practice

    function addPractice() {
        if (practiceCount < 10) {
            practiceCount += 1
        }
    }

    function getStateText() {
        if (currentState === StudyState.Preview) {
            return "当前阶段:预习"
        }

        if (currentState === StudyState.Practice) {
            return "当前阶段:练习"
        }

        return "当前阶段:复习"
    }

    Rectangle {
        width: 450
        height: 300
        radius: 15
        color: mainWindow.panelColor

        anchors.centerIn: parent

        Text {
            anchors.top: parent.top
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.topMargin: 30

            text: "学生:" + mainWindow.studentName

            font {
                pixelSize: 24
                bold: true
            }
        }

        Text {
            anchors.centerIn: parent

            text: mainWindow.getStateText() +
                  "\n练习次数:" +
                  mainWindow.practiceCount +
                  "\n学习进度:" +
                  Math.round(mainWindow.progressValue * 100) +
                  "%"

            horizontalAlignment: Text.AlignHCenter
            font.pixelSize: 20
        }

        Button {
            text: "增加练习"

            anchors.left: parent.left
            anchors.bottom: parent.bottom
            anchors.leftMargin: 30
            anchors.bottomMargin: 25

            onClicked: {
                mainWindow.addPractice()
            }
        }

        Button {
            text: "重置"

            anchors.right: parent.right
            anchors.bottom: parent.bottom
            anchors.rightMargin: 30
            anchors.bottomMargin: 25

            onClicked: {
                mainWindow.practiceCount = 0
            }
        }
    }

    onPracticeCountChanged: {
        console.log("当前练习次数:", practiceCount)
    }

    Component.onCompleted: {
        console.log("窗口创建完成")
        console.log("初始学习状态:", currentState)
    }
}

这个示例用到了:

  • 枚举
  • int
  • real
  • bool
  • string
  • color
  • JavaScript 函数
  • 属性绑定
  • 条件判断
  • 作用域
  • id.属性
  • 属性组
  • 信号处理器
  • 代码风格

十五、本节总结

本节内容可以归纳为以下几个重点。

枚举

text 复制代码
用于定义一组固定命名选项。

基本类型

text 复制代码
用于保存整数、字符串、布尔值、小数等数据。

对象类型

text 复制代码
用于创建 Rectangle、Button、Text 等具体对象。

JavaScript

text 复制代码
用于辅助处理界面逻辑、函数、表达式和数据。

自定义 QML 组件

text 复制代码
用于封装重复界面,并向外提供可设置的属性。

作用域

text 复制代码
决定当前代码能够访问哪些对象和属性。

代码风格

text 复制代码
不会改变程序结果,但会影响代码的可读性和维护性。

十六、快速复习表

知识点 核心作用
enum 定义固定选项
int 保存整数
bool 保存真假状态
real 保存小数
string 保存字符串
color 保存颜色
url 保存路径或网址
var 保存多种类型的数据
对象类型 创建具体 QML 对象
JavaScript 数组 保存多个数据
JavaScript 对象 保存多个字段
function 封装处理逻辑
JS 文件导入 分离 JavaScript 代码
自定义组件 封装和复用界面
parent 引用直接父对象
id.属性 明确访问指定对象
属性组 集中设置相关属性
代码风格 提高可读性与维护性

十七、一句话总结

QML 使用基本类型保存数据,使用对象类型构建界面,使用 JavaScript 辅助处理逻辑,使用自定义组件复用界面,并通过清晰统一的代码风格提高项目的可维护性。