编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • Android提升进阶

  • iOS开发和进阶

  • Web开发和进阶

  • Linux应用开发

    • README
    • QML基础入门

      • README
      • Qml基础概念
      • Qml基础语法
      • Qml基础组件
      • Qml控件介绍
      • Qml高级功能
        • 3.1 基础可视项目
          • 3.1.1 Item
          • 3.1.2 Text
          • 3.1.3 TextInput
          • 3.1.4 TextEdit
          • 3.1.5 Image
        • 3.2 布局管理
          • 3.2.1 容器Rectangle
          • 3.2.2 基于锚的布局
          • 3.2.3 定位器
        • 3.3 键盘输入
          • 3.3.1 键盘输入概念
          • 3.3.2 键盘输入案例
          • 3.3.3 案例说明
          • 3.3.4 键盘注意事项
        • 3.4 事件处理
          • 3.4.1 MouseArea事件
          • 3.4.2 键盘事件
          • 3.4.3 触摸事件
          • 3.4.4 手势识别
          • 3.4.5 自定义事件
          • 3.4.6 事件传播
          • 3.4.7 事件过滤器
          • 3.4.8 Keys按键事件
        • 3.5 动态加载组件
          • 3.5.1 Qt.createQmlObject
          • 3.5.2 createObject
          • 3.5.3 Loader方式
          • 3.5.4 Repeater方式
          • 3.5.5 JavaScript方式
        • 3.6 导航容器
          • 3.6.1 StackView介绍
          • 3.6.2 核心功能
          • 3.6.3 StackView案例
          • 3.6.4 注意事项
          • 3.6.5 扩展功能
        • 3.7 页面声明周期
          • 3.7.1 组件创建和销毁
          • 3.7.2 页面加载
          • 3.7.3 页面显示
          • 3.7.4 页面激活
          • 3.7.5 页面销毁
          • 3.7.6 动态加载和卸载
          • 3.7.7 窗口生命周期
          • 3.7.8 状态管理
          • 3.7.9 生命周期总结
        • 3.8 异步编程技巧
          • 3.8.1 WorkerScript
          • 3.8.2 Timer定时器
          • 3.8.3 Qt.callLater
          • 3.8.4 C++和QML结合
          • 3.8.5 JavaScript异步
          • 3.8.6 异步编程总结
      • Canvas绘制
      • QML和C++
      • 多媒体应用
      • 模型和视图
      • 应用层开发
      • 图形和动画
    • QT核心库实践

    • Linux实践开发

  • Apps
  • Linux应用开发
  • QML基础入门
杨充
2025-08-29
目录

Qml高级功能

# 03.Quick基础

# 目录介绍

  • 3.4 事件处理
    • 3.4.1 MouseArea事件
    • 3.4.2 键盘事件
    • 3.4.3 触摸事件
    • 3.4.4 手势识别
    • 3.4.5 自定义事件
    • 3.4.6 事件传播
    • 3.4.7 事件过滤器
    • 3.4.8 Keys按键事件
  • 3.5 动态加载组件
    • 3.5.1 Qt.createQmlObject
    • 3.5.2 createObject
    • 3.5.3 Loader方式
    • 3.5.4 Repeater方式
    • 3.5.5 JavaScript方式
  • 3.8 异步编程技巧
    • 3.8.1 WorkerScript
    • 3.8.2 Timer定时器
    • 3.8.3 Qt.callLater
    • 3.8.4 C++和QML结合
    • 3.8.5 JavaScript异步
    • 3.8.6 动态加载

# 3.1 基础可视项目

# 3.1.1 Item

Item 是一个非常重要的基础类型。它是所有可视化元素的基类,但本身并不直接绘制任何内容。

Item 提供了一个容器和布局的基础,用于组织和管理其他可视化元素。Item 的使用场景:

  • 布局容器: 用于组织和管理子元素的位置和大小。
  • 事件处理: 用于捕获鼠标或触摸事件。
  • 变换和动画: 用于实现复杂的动态效果。
  • 不可见的逻辑容器: 用于逻辑分组,而不直接显示内容。

Item 是 Qt Quick 中的一个核心类型,位于 QtQuick 模块中。它是一个不可见的容器,主要用于:

  • 定义一个矩形区域。
  • 组织和管理子元素。
  • 提供基本的属性(如位置、大小、锚点等)。
  • 处理输入事件(如鼠标和触摸事件)。

Item 本身不会绘制任何内容,但它可以作为其他可视化元素(如 Rectangle、Image、Text 等)的父级。

Item常用属性,几何属性:

  • x 和 y: 定义 Item 的位置(相对于父级)。
  • width 和 height: 定义 Item 的宽度和高度。
  • z: 定义 Item 的堆叠顺序,值越大,越靠前显示。

Item常用属性,锚点属性:

  • anchors,用于将 Item 锚定到父级或其他元素。

Item常用属性,可见性属性

  • visible: 控制 Item 是否可见(true 或 false)。
  • opacity: 控制 Item 的透明度(范围为 0.0 到 1.0)。

Item常用属性,变换属性

  • scale: 控制 Item 的缩放比例。
  • rotation: 控制 Item 的旋转角度(以度为单位)。
  • transform: 用于应用复杂的变换(如平移、旋转、缩放等)。

Item子元素管理

Item 可以作为其他元素的父级,子元素会继承父级的几何属性(如位置和变换)。

# 3.1.2 Text

Text 是用于显示文本内容的 QML 类型。Text 类型允许你在用户界面中显示静态或动态文本,并提供了许多属性来控制文本的外观、样式和布局。

  1. 基本用法:Text综合案例,展示各种用法

Text 类型用于显示文本内容。你可以设置文本内容、字体、颜色、大小、对齐方式等属性。 以下是一个简单的 Text 示例:

Text {
    text: "Hover over this text to change color"
    font.pixelSize: 20
    color: "black"
    font.bold: true
    horizontalAlignment: Text.AlignHCenter

    //创建一个鼠标悬停效果,当鼠标悬停在文本上时,改变文本的颜色。
    MouseArea {
        anchors.fill: parent
        hoverEnabled: true
        onEntered: {
            parent.color = "red"
        }
        onExited: {
            parent.color = "black"
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  1. 文本样式:
  • 你可以通过设置 font.family、font.bold、font.italic 等属性来定义文本的字体样式。
  • 使用 font.pixelSize 或 font.pointSize 属性可以设置文本的字体大小。
  1. 文本布局:
  • 通过设置 horizontalAlignment 和 verticalAlignment 属性,你可以控制文本的水平和垂直对齐方式。
  • 使用 wrapMode 属性可以指定文本的换行方式,如自动换行或截断。
  1. 文本格式化:
  • Text 类型支持基本的文本格式化,如加粗、斜体、下划线等。
  • 你可以使用 style 属性来设置文本的格式化样式。
  1. 动态文本:
  • 你可以使用 JavaScript 表达式或绑定来动态设置文本内容,以实现根据数据变化而更新的文本显示。
  • 例如,你可以将文本内容绑定到一个变量或属性,使得文本内容随着变量的改变而更新。
  1. 交互和事件处理:
  • 你可以为 Text 添加交互行为,如鼠标点击事件、悬停效果等。
  • 通过处理鼠标事件或触摸事件,你可以实现与用户的交互。
  1. 多语言支持:
  • Text 类型支持多语言文本显示,你可以使用 qsTr() 函数来实现国际化和本地化。

# 3.1.3 TextInput

TextInput 是用于接收用户输入文本的 QML 类型。TextInput 类型允许用户在应用程序中输入文本,并提供了许多属性和信号来管理和响应用户输入。

  1. 基本用法:

TextInput 类型用于接收用户输入的文本。用户可以在 TextInput 中输入文本,并应用程序可以获取用户输入的内容。

TextInput {
  width: 200
  placeholderText: "Enter text here"
  onTextChanged: {
      console.log("User input: " + text)
  }
}
1
2
3
4
5
6
7
  1. 属性和信号:
  • TextInput 类型提供了许多属性,如 text(用户输入的文本内容)、placeholderText(占位文本)、cursorPosition(光标位置)等。
  • 通过处理信号,如 onTextChanged、onEditingFinished 等,你可以响应用户输入的变化和完成编辑操作。
  1. 键盘输入:
  • TextInput 类型会自动弹出软键盘,以便用户输入文本。你可以通过设置 focus 属性来控制 TextInput 的焦点状态。
  • 你可以使用 inputMethodHints 属性来指定输入法提示,以告知输入法如何显示键盘。
  1. 文本格式化和验证:
  • 你可以使用 validator 属性来指定文本验证器,以限制用户输入的内容。
  • 通过设置 inputMask 属性,你可以定义文本输入的格式,如日期、电话号码等。
  1. 密码输入:
  • 如果需要接收密码或其他敏感信息,你可以将 echoMode 属性设置为 TextInput.Password,以隐藏用户输入的文本。
  1. 多行输入:
  • 除了单行输入,TextInput 类型还支持多行文本输入。你可以设置 wrapMode 属性来控制文本的换行方式。
  1. 样式和外观:
  • 你可以通过设置 font、color、background 等属性来自定义 TextInput 的外观和样式。
  • 使用 readOnly 属性可以将 TextInput 设置为只读模式,禁止用户编辑文本内容。

# 3.1.4 TextEdit

TextEdit 是用于显示和编辑多行文本的 QML 类型。TextEdit 类型允许用户在应用程序中输入、编辑和显示多行文本内容,并提供了许多属性和信号来管理和响应用户的文本操作。

  1. 基本用法:

TextEdit 类型用于显示和编辑多行文本内容。用户可以在 TextEdit 中输入、编辑和查看多行文本。

TextEdit {
  width: 300
  height: 200
  text: "Initial text content"
  onTextChanged: {
      console.log("Text content changed: " + text)
  }
}
1
2
3
4
5
6
7
8
  1. 属性和信号:
  • TextEdit 类型提供了许多属性,如 text(文本内容)、font(字体样式)、wrapMode(换行方式)等。
  • 通过处理信号,如 onTextChanged、onCursorPositionChanged 等,你可以响应用户对文本内容的操作和变化。
  1. 键盘输入和编辑:
  • TextEdit 类型支持多行文本输入和编辑。用户可以在 TextEdit 中输入、删除、复制、粘贴文本内容。
  • 你可以设置 readOnly 属性来将 TextEdit 设置为只读模式,禁止用户编辑文本内容。
  1. 文本格式化和样式:
  • 你可以使用 font、color、highlightedText 等属性来自定义 TextEdit 中文本的样式和外观。
  • 通过设置 textFormat 属性,你可以指定文本的格式化方式,如纯文本、富文本等。
  1. 滚动和布局:
  • 如果文本内容超出 TextEdit 的显示区域,TextEdit 会自动添加滚动条以便用户查看全部内容。
  • 你可以设置 wrapMode 属性来控制文本的换行方式,以适应 TextEdit 的大小。
  1. 文本选择和操作:
  • 用户可以通过鼠标或触摸操作来选择文本内容,并执行复制、剪切、粘贴等操作。
  • 通过设置 selectByMouse 属性,你可以控制用户是否可以使用鼠标选择文本。
  1. 撤销和重做:
  • TextEdit 类型支持撤销和重做操作,用户可以通过快捷键或菜单操作来撤销或重做文本编辑操作。

# 3.1.5 Image

Image 写一个包含布局大小,位置,阴影效果,圆角,有交互事件的综合案例

// 图片元素
Image {
    id: image
    width: parent.width
    height: parent.height
    source: "https://pics4.baidu.com/feed/728da9773912b31b37cbc23bb3752575dbb4e1fd.jpeg" // 图片 URL
    fillMode: Image.PreserveAspectCrop // 保持宽高比并裁剪
    clip: true // 裁剪超出部分
    radius: 10 // 圆角效果
    layer.enabled: true
    layer.effect: OpacityMask {
        maskSource: Rectangle {
            width: image.width
            height: image.height
            radius: image.radius
        }
    }

    // 鼠标悬停效果
    MouseArea {
        anchors.fill: parent
        hoverEnabled: true
        onEntered: {
            image.scale = 1.05 // 放大图片
        }
        onExited: {
            image.scale = 1.0 // 恢复原大小
        }
        onClicked: {
            console.log("Image clicked!");
        }
    }

    // 缩放动画
    Behavior on scale {
        NumberAnimation { duration: 200 } // 200ms 动画
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 3.2 布局管理

在 Qt Quick 中,布局管理是用于组织和排列界面元素的核心机制。

Qt Quick 提供了多种布局管理器(如 Row、Column、Grid、Flow 等)以及锚点系统(Anchors)来实现灵活的界面布局。

# 3.2.1 容器Rectangle

Rectangle 是一个常用的 QML 类型,用于创建矩形形状的图形元素。

Rectangle 类型允许你定义矩形的外观、位置、大小和其他属性,以便在用户界面中显示矩形元素。

  1. 基本用法:,Rectangle 类型用于创建矩形形状的图形元素。你可以设置矩形的宽度、高度、颜色、边框等属性。

以下是一个简单的 Rectangle 示例:

Rectangle {
    id:root
    x:212
    y:12
    width: 76
    height: 96
    visible: true
    //gradient 属性用于定义渐变效果,这里使用了线性渐变(Gradient)。
    gradient: Gradient {
        GradientStop { position: 0.0; color: "lightsteelblue" }
        GradientStop { position: 1.0; color: "red" }
    }
    border.color: "green"
    border.width: 4
    radius: 20
    //子元素
    Text {
         anchors.centerIn: parent
         text: "Gradient"
         color: "white"
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  1. 位置和布局:
  • 你可以使用 x 和 y 属性来设置矩形的位置,以确定矩形在父元素中的位置。
  • 此外,你还可以使用布局属性(如 anchors)来实现更灵活的布局。
  1. 边框和描边:
  • 通过设置 border、border.color 和 border.width 属性,你可以为矩形添加边框。
  • 你还可以使用 radius 属性来设置矩形的圆角半径,使矩形具有圆角边框。
  1. 阴影效果:
  • Rectangle 类型还支持阴影效果,你可以使用 dropShadow 属性来添加阴影效果。
  • 通过设置阴影的颜色、偏移量和模糊半径,可以实现不同样式的阴影效果。
  1. 交互和动画:
  • 你可以为 Rectangle 添加交互行为,如鼠标点击事件、拖动事件等。
  • 通过使用动画属性和状态,你可以为矩形添加动画效果,使其在状态变化时产生平滑的过渡效果。
  1. 嵌套元素:
  • 你可以在 Rectangle 中嵌套其他 QML 元素,以构建更复杂的用户界面结构。
  • 例如,在 Rectangle 中嵌套一个 Text 元素来显示文本内容。

# 3.2.2 基于锚的布局

使用 Anchors 可以实现相对定位,将元素相对于其他元素或父元素进行定位。

通过设置元素的 anchors 属性,你可以定义元素的位置和大小,使得元素能够根据其他元素的位置自动调整。

Anchors基本属性,以下是 anchors 的常用属性:

  1. 锚定到父组件:
  • anchors.top:锚定到父组件的顶部。
  • anchors.bottom:锚定到父组件的底部。
  • anchors.left:锚定到父组件的左侧。
  • anchors.right:锚定到父组件的右侧。
  • anchors.horizontalCenter:锚定到父组件的水平中心。
  • anchors.verticalCenter:锚定到父组件的垂直中心。
  • anchors.centerIn:锚定到父组件的中心。
  1. 锚定到兄弟组件:
  • anchors.top:锚定到兄弟组件的顶部。
  • anchors.bottom:锚定到兄弟组件的底部。
  • anchors.left:锚定到兄弟组件的左侧。
  • anchors.right:锚定到兄弟组件的右侧。
  1. 边距:
  • anchors.margins:设置所有边的边距。
  • anchors.topMargin:设置顶部的边距。
  • anchors.bottomMargin:设置底部的边距。
  • anchors.leftMargin:设置左侧的边距。
  • anchors.rightMargin:设置右侧的边距。
  1. 填充:
  • anchors.fill:填充整个父组件。
  1. 对齐:
  • anchors.alignWhenCentered:当使用 centerIn 时,是否对齐到像素网格。

Anchors注意事项

  1. 避免锚定冲突:不要同时设置 anchors.top 和 anchors.bottom,或者 anchors.left 和 anchors.right。
  2. 动态调整布局: 可以使用 Binding 或 JavaScript 动态调整 anchors 属性。
  3. 性能优化:对于复杂的布局,anchors 的性能通常优于手动设置 x、y、width 和 height。

# 3.2.3 定位器

Qt Quick 中的 Positioner 类型(如 Column, Row, Grid)可以帮助你自动排列子元素。

布局管理器是用于自动排列子元素的容器。Qt Quick 提供了几种基本的布局类型,如 Column、Row、Grid 等,用于垂直、水平和网格布局。

Row (水平布局)将子元素水平排列。

import QtQuick 2.15

Row {
    id: colorRow
    spacing: 10 //通过 spacing 属性设置按钮之间的间距。
    layoutDirection: Qt.LeftToRight // 布局方向(从左到右或从右到左)
    anchors.bottom: paddingRow.top
    anchors.horizontalCenter: parent.horizontalCenter
    padding: 10 // 内边距
    
    Button {
        text: "Light"
        onClicked: toolbarBackground.color = "#f0f0f0"
    }
    
    Button {
        text: "Dark"
        onClicked: toolbarBackground.color = "#333333"
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Column (垂直布局)将子元素垂直排列。

import QtQuick 2.15

Column {
    spacing: 10 // 子元素之间的间距

    Rectangle { width: 50; height: 50; color: "red" }
    Rectangle { width: 50; height: 50; color: "green" }
    Rectangle { width: 50; height: 50; color: "blue" }
}
1
2
3
4
5
6
7
8
9

Flow (流式布局)根据可用空间自动换行排列子元素。

import QtQuick 2.15

Flow {
    spacing: 10 // 子元素之间的间距

    Rectangle { width: 50; height: 50; color: "red" }
    Rectangle { width: 50; height: 50; color: "green" }
    Rectangle { width: 50; height: 50; color: "blue" }
    Rectangle { width: 50; height: 50; color: "yellow" }
}
1
2
3
4
5
6
7
8
9
10

# 3.3 键盘输入

# 3.3.1 键盘输入概念

  1. Keys 附加属性:用于捕获和处理键盘事件。常用事件:
  • onPressed:按键按下时触发。
  • onReleased:按键释放时触发。
  • onShortcutOverride:快捷键被按下时触发。
  1. KeyEvent 对象:表示键盘事件,包含以下常用属性:
  • key:按键的键值(如 Qt.Key_Enter)。
  • text:按键对应的文本(如字母或数字)。
  • modifiers:修饰键(如 Shift、Ctrl 等)。
  1. 输入焦点管理:
  • 使用 focus 属性控制组件是否接收键盘输入。
  • 使用 focusScope 管理焦点范围。
  1. 快捷键:
  • 使用 Shortcut 组件定义快捷键。

# 3.3.2 键盘输入案例

Rectangle {
    width: 600
    height: 100
    color: "#f0f0f0"
    focus: true //设置焦点接受键盘事件
    Keys.onPressed: {
        console.log("Key pressed:", event.key, "Text:", event.text);
        if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
            console.log("Enter key pressed!");
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 3.3.3 案例说明

捕获键盘事件: 使用 Keys.onPressed 捕获按键事件,并打印按键的键值和文本。

# 3.3.4 键盘注意事项

  1. 焦点管理:确保组件设置了 focus: true 才能接收键盘事件。 使用 focusScope 管理焦点范围。
  2. 快捷键冲突:避免快捷键与其他组件的快捷键冲突。
  3. 平台差异:不同平台的键盘事件可能有所不同,需进行兼容性测试。
  4. 性能优化:对于复杂的键盘事件处理,避免在事件处理函数中执行耗时操作。

# 3.4 事件处理

事件处理是响应用户交互(如鼠标点击、键盘输入、触摸事件等)的核心机制。

Qt Quick 提供了多种方式来处理事件,包括信号槽机制、事件处理器和手势识别等。

QML 提供了事件处理器(Event Handlers)来直接处理特定事件。事件处理器以 on 开头,后跟事件名称。

# 3.4.1 MouseArea事件

MouseArea 是一个用于处理鼠标(或触摸)事件的组件。它可以附加到任何可视元素(如 Rectangle、Image 等),用于监听鼠标点击、拖动、悬停等操作。

MouseArea 允许你定义鼠标事件的处理函数,如 onClicked、onPressed、onReleased 等。

Rectangle {
    width: 200
    height: 100
    color: "lightblue"

    MouseArea {
        anchors.fill: parent
        onClicked: console.log("Mouse clicked!")
        onDoubleClicked: console.log("Mouse double clicked!")
        onPressed: console.log("Mouse pressed!")
        onReleased: console.log("Mouse released!")
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

MouseArea 提供了以下常用属性和信号处理器:

属性:

  • enabled:是否启用 MouseArea(默认为 true)。
  • hoverEnabled:是否启用悬停事件(默认为 false)。
  • acceptedButtons:指定接收哪些鼠标按钮事件(如 Qt.LeftButton、Qt.RightButton)。
  • pressed:鼠标是否按下(true 表示按下,false 表示释放)。
  • containsMouse:鼠标是否在 MouseArea 区域内。

信号处理器:

  • onClicked:鼠标点击时触发。
  • onDoubleClicked:鼠标双击时触发。
  • onPressed:鼠标按下时触发。
  • onReleased:鼠标释放时触发。
  • onEntered:鼠标进入 MouseArea 区域时触发。
  • onExited:鼠标离开 MouseArea 区域时触发。
  • onPositionChanged:鼠标在 MouseArea 区域内移动时触发。

# 3.4.2 键盘事件

通过在元素上设置 Keys.onPressed 或 Keys.onReleased 来处理键盘事件。可以捕获特定按键的按下或释放事件,并执行相应的操作。

使用 Keys 附加属性处理键盘事件:

import QtQuick 2.15

Rectangle {
    width: 200
    height: 100
    color: "lightblue"
    focus: true

    Keys.onPressed: {
        if (event.key === Qt.Key_Space) {
            console.log("Space key pressed!")
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 3.4.3 触摸事件

使用 MultiPointTouchArea 处理多点触摸事件,MultiPointTouchArea 允许你处理多点触摸事件,如缩放、旋转等。

import QtQuick 2.15

Rectangle {
    width: 200
    height: 100
    color: "lightblue"

    MultiPointTouchArea {
        anchors.fill: parent
        onTouchUpdated: {
            for (var i = 0; i < touchPoints.length; i++) {
                console.log("Touch point:", touchPoints[i].x, touchPoints[i].y)
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 3.4.4 手势识别

Qt Quick 提供了手势识别器(Gesture Recognizers)来处理复杂的手势,如滑动、捏合等。

使用 SwipeView 或 SwipeArea 处理滑动手势:

import QtQuick 2.15
import QtQuick.Controls 2.15

SwipeView {
    width: 200
    height: 100

    Rectangle { color: "red" }
    Rectangle { color: "green" }
    Rectangle { color: "blue" }
}
1
2
3
4
5
6
7
8
9
10
11

使用 PinchArea 处理捏合手势:

import QtQuick 2.15

Rectangle {
    width: 200
    height: 100
    color: "lightblue"

    PinchArea {
        anchors.fill: parent
        onPinchUpdated: {
            console.log("Pinch scale:", pinch.scale)
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 3.4.5 自定义事件

可以通过继承 Item 或 Rectangle 创建自定义事件处理器。

import QtQuick 2.15

Rectangle {
    width: 200
    height: 100
    color: "lightblue"

    signal customMouseEvent(int x, int y)

    MouseArea {
        anchors.fill: parent
        onClicked: parent.customMouseEvent(mouse.x, mouse.y)
    }

    onCustomMouseEvent: {
        console.log("Custom mouse event at:", x, y)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 3.4.6 事件传播

QML 中的事件传播遵循父子关系。事件会从子元素向上传播到父元素,直到被处理或到达根元素。

使用 event.accepted = true 阻止事件继续传播。

# 3.4.7 事件过滤器

使用 Item 的 eventFilter 方法过滤事件。允许你在事件到达元素之前拦截和处理事件。

# 3.4.8 Keys按键事件

Keys 附加属性用于处理键盘按键事件。通过 Keys,可以监听和处理用户按下、释放或长按键盘按键的操作。以下是 Keys 的详细使用方法:

Keys 是一个附加属性,通常与 Item 或 FocusScope 一起使用。它提供了以下常用事件处理器:

  • onPressed:当按键按下时触发。
  • onReleased:当按键释放时触发。
  • onShortcutOverride:当按键事件可能被系统快捷键覆盖时触发。
Rectangle {
    width: 200
    height: 100
    color: "lightblue"
    focus: true // 必须设置焦点才能接收按键事件

    Keys.onPressed: {
        console.log("按键按下:", event.key);
        if (event.key === Qt.Key_Return) {
            console.log("回车键按下");
        }
    }

    Keys.onReleased: {
        console.log("按键释放:", event.key);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

Qt 提供了一系列按键常量,用于识别特定的按键。以下是一些常用的按键常量:

  • Qt.Key_Return:回车键。
  • Qt.Key_Enter:小键盘上的回车键。
  • Qt.Key_Escape:Esc 键。
  • Qt.Key_Space:空格键。
  • Qt.Key_Backspace:退格键。
  • Qt.Key_Delete:删除键。
  • Qt.Key_Left:左箭头键。
  • Qt.Key_Right:右箭头键。
  • Qt.Key_Up:上箭头键。
  • Qt.Key_Down:下箭头键。
  • Qt.Key_A 到 Qt.Key_Z:字母键。
  • Qt.Key_0 到 Qt.Key_9:数字键。

阻止事件传播:默认情况下,按键事件会向上传播到父组件。可以通过 event.accepted = true 阻止事件传播。

Rectangle {
    width: 200
    height: 100
    color: "lightblue"
    focus: true

    Keys.onPressed: {
        if (event.key === Qt.Key_Space) {
            console.log("空格键按下,事件被阻止");
            event.accepted = true; // 阻止事件传播
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 3.5 动态加载组件

根据具体需求选择合适的方法,可以高效地实现 QML 中的动态创建功能。

方法 适用场景 优点 缺点
Qt.createQmlObject 从字符串动态创建对象 灵活 性能较差
Component 需要频繁创建对象的场景 性能较好 需要提前定义模板
Loader 动态加载和切换组件 适合动态切换组件 只能加载一个组件
Repeater 生成多个相同类型的组件 简单易用 组件类型必须相同

# 3.5.1 Qt.createQmlObject

Qt.createQmlObject 允许从字符串形式的 QML 代码动态创建对象。

object Qt.createQmlObject(string qml, object parent, string filepath)
1
  • qml:字符串形式的 QML 代码。适用于需要在运行时动态生成 UI 组件或逻辑的场景。
  • parent:新创建对象的父对象。新创建的对象需要指定一个父对象,用于管理其生命周期。
  • filepath(可选):用于调试的源文件路径,通常设置为创建 QML 代码的文件路径。便于调试时定位问题。

示例:动态创建一个矩形。在窗口加载完成后,动态创建一个红色的矩形,并将其添加到窗口中。this 是父对象,表示新创建的矩形的父对象是当前窗口。

Component.onCompleted: {
    // QML 代码字符串
    var qmlCode = `
        import QtQuick 2.15
        Rectangle {
            width: 100
            height: 100
            color: "red"
        }
    `;

    // 动态创建对象并添加到窗口中
    var newObject = Qt.createQmlObject(qmlCode, this, "dynamicRect");
    console.log("动态创建的对象:", newObject);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  • 优点:灵活,可以直接从字符串创建对象。
  • 缺点:性能较差,适合创建简单对象。

注意事项

  1. 性能问题:频繁使用 Qt.createQmlObject 可能会影响性能,尤其是在创建复杂对象时。 对于需要频繁创建的对象,建议使用 Component 或 Loader。
  2. 作用域问题:动态创建的对象的作用域受限于其父对象。如果父对象被销毁,动态创建的对象也会被销毁。
  3. 错误处理:如果 QML 代码字符串有语法错误,Qt.createQmlObject 会抛出异常。建议使用 try-catch 捕获异常。
  4. 调试支持:通过 filepath 参数指定源文件路径,便于调试时定位问题。

# 3.5.2 createObject

Component + createObject:使用 Component 定义模板,然后通过 createObject 动态创建对象。性能优于 Qt.createQmlObject,适合需要频繁创建对象的场景。

Component 是 QML 中的一种模板机制,可以通过 createObject 方法动态创建对象。示例:动态创建一个按钮

// 定义组件模板
Component {
  id: buttonComponent
  Button {
    text: "点击我"
    onClicked: console.log("按钮被点击了!");
  }
}

Component.onCompleted: {
  // 动态创建对象并添加到窗口中
  var newObject = buttonComponent.createObject(this, { x: 150, y: 100 });
  console.log("动态创建的对象:", newObject);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • 优点:性能较好,适合需要频繁创建对象的场景。
  • 缺点:需要提前定义 Component。

# 3.5.3 Loader方式

在 Qt Quick (QML) 中,Loader 是一个动态加载和卸载组件的容器。它允许你在运行时根据需要加载不同的 QML 文件或组件,从而优化资源使用和提升性能。Loader 特别适合用于实现动态界面、懒加载或按需加载的场景。

Loader核心属性:

  1. source:指定要加载的 QML 文件或组件的路径。例如:source: "MyComponent.qml"。
  2. sourceComponent:指定要加载的组件对象(通常是 Component 类型)。例如:sourceComponent: myComponent。
  3. active: 控制 Loader 是否处于活动状态。 如果为 true,Loader 会加载 source 或 sourceComponent 指定的内容;如果为 false,Loader 会卸载内容。
  4. item: 获取 Loader 当前加载的组件实例。 可以通过 item 访问加载组件的属性和方法。
  5. asynchronous:控制是否异步加载组件。如果为 true,组件会在后台线程中加载,避免阻塞 UI 线程。
  6. status:表示 Loader 的当前状态,有以下可能值:
  • Loader.Null:未加载任何内容。
  • Loader.Ready:组件已加载完成。
  • Loader.Loading:组件正在加载。
  • Loader.Error:加载失败。

Loader常用方法

  1. setSource(source, properties):动态设置 source 并加载组件。properties 是一个可选参数,用于传递初始属性值给加载的组件。
  2. resetSource():重置 source,卸载当前加载的组件。

以下是一个综合案例,展示了如何使用 Loader 动态加载组件、传递属性以及控制加载状态。

// 主布局
Column {
  spacing: 20
  anchors.centerIn: parent

  // 使用 Loader 加载组件
  Loader {
      id: loader
      width: 600
      height: 200
      onStatusChanged: {
          if (status === Loader.Ready) {
              console.log("Component loaded successfully!");
          } else if (status === Loader.Error) {
              console.log("Failed to load component!");
          }
      }
  }

  // 1. 动态加载组件
  Row {
      spacing: 10
      Button {
          text: "动态加载组件"
          onClicked: {
              loader.source = "NewPage.qml";
          }
      }
      Button {
          text: "卸载组件"
          onClicked: {
              loader.source = ""; // 卸载组件
          }
      }
  }


  // 2. 传递属性给加载的组件
  Button {
      text: "传递属性给加载的组件"
      onClicked: {
          loader.setSource("NewPage.qml", { "message": "Hello from Loader!" });
      }
  }

  Component {
      id: dynamicComponent
      Rectangle {
          width: 600
          height: 100
          color: "lightgreen"
          Text {
              text: "这个是一个组件"
              anchors.centerIn: parent
              font.pixelSize: 24
          }
      }
  }

  // 3.使用 sourceComponent 加载组件
  Button {
      text: "Load Dynamic Component"
      onClicked: {
          loader.sourceComponent = dynamicComponent;  //加载组件
      }
  }
  Button {
      text: "Unload Dynamic Component"
      onClicked: {
          loader.sourceComponent = undefined; // 卸载组件
      }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

监听加载状态:使用 onStatusChanged 监听 Loader 的加载状态,并在加载成功或失败时打印消息。

Loader注意事项:

  1. 资源管理:及时卸载不再使用的组件,避免内存泄漏。
  2. 性能优化:对于复杂的组件,可以使用 asynchronous: true 异步加载,避免阻塞 UI 线程。
  3. 组件生命周期:加载的组件的生命周期与 Loader 绑定,卸载时组件会被销毁。
  4. 错误处理:监听 status 属性,处理加载失败的情况。

扩展建议

  • 可以将 Loader 用于实现动态界面切换,如选项卡、向导页面等。
  • 可以将 Loader 与 SwipeView 或 StackView 结合,实现更复杂的导航逻辑。
  • 可以将 Loader 用于懒加载,仅在需要时加载组件,提升启动性能。

# 3.5.4 Repeater方式

Repeater 是一种用于动态生成多个相同类型组件的机制,通常与模型(model)结合使用。示例:动态生成多个矩形

// 使用 Repeater 动态生成多个矩形
Row {
  spacing: 10
  Repeater {
      model: 5 // 生成 5 个矩形
      Rectangle {
          width: 50
          height: 50
          color: index % 2 === 0 ? "red" : "blue"
      }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

优点:适合生成多个相同类型的组件。

缺点:组件类型必须相同。

# 3.5.5 JavaScript方式

# 3.6 导航容器

# 3.6.1 StackView介绍

在 QML 中,StackView 是一个基于堆栈的导航容器,非常适合用于实现页面切换。

它支持页面的推入(push)、弹出(pop)和替换(replace)操作,类似于移动应用中的导航逻辑。

# 3.6.2 核心功能

  1. push(item):将一个新页面推入堆栈,显示在顶部。例如:stackView.push("Page2.qml")。
  2. pop(item): 弹出当前页面,返回到上一个页面。例如:stackView.pop()。
  3. replace(item):用新页面替换当前页面,堆栈深度不变。例如:stackView.replace("Page3.qml")。
  4. clear():清空堆栈中的所有页面。
  5. initialItem:设置 StackView 的初始页面。
  6. depth:获取当前堆栈中的页面数量。
  7. currentItem:获取当前显示的页面实例。

# 3.6.3 StackView案例

以下是一个完整的案例,展示了如何使用 StackView 实现页面切换。

// 主布局
StackView {
    id: stackView
    initialItem: page1
    anchors.fill: parent
}

// 页面 1
Component {
    id: page1
    Page {
        title: "Page 1"
        Column {
            spacing: 20
            anchors.centerIn: parent

            Button {
                text: "Go to Page 2"
                onClicked: {
                    stackView.push(page2); // 推入页面 2
                }
            }
        }
    }
}



// 页面 2
Component {
    id: page2
    Page {
        title: "Page 2"
        Column {
            spacing: 20
            anchors.centerIn: parent

            Button {
                text: "Go Back"
                onClicked: {
                    stackView.pop(); // 弹出当前页面
                }
            }

            Button {
                text: "Go to Page 3"
                onClicked: {
                    //stackView.push(page3); // 推入页面 3
                    stackView.push("Container.qml");
                }
            }
        }
    }
}

// 页面 3
Component {
    id: page3
    Page {
        title: "Page 3"
        Column {
            spacing: 20
            anchors.centerIn: parent

            Button {
                text: "Go Back"
                onClicked: {
                    stackView.pop(); // 弹出当前页面
                }
            }

            Button {
                text: "Go to Page 1"
                onClicked: {
                    stackView.replace(page1); // 替换为页面 1
                }
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

# 3.6.4 注意事项

  1. 页面生命周期:当页面被推入堆栈时,它会创建并显示;当页面被弹出时,它会被销毁。
  2. 传递参数: 可以通过 push 或 replace 方法的第二个参数传递初始属性值给新页面。 例如:
stackView.push("Page2.qml", { "message": "Hello from Page 1!" });
1
  1. 动画效果:StackView 默认支持页面切换的动画效果,可以通过 popEnter、popExit、pushEnter 和 pushExit 属性自定义动画。
  2. 清空堆栈:使用 clear 方法可以清空堆栈中的所有页面。

# 3.6.5 扩展功能

1. 传递参数给页面

// 推入页面并传递参数
stackView.push("Page2.qml", { "message": "Hello from Page 1!" });

// 在 Page2.qml 中接收参数
Page {
    property string message
    Label {
        text: message
        anchors.centerIn: parent
    }
}
1
2
3
4
5
6
7
8
9
10
11

2. 自定义页面切换动画

StackView {
    id: stackView
    anchors.fill: parent

    pushEnter: Transition {
        NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 200 }
    }
    pushExit: Transition {
        NumberAnimation { property: "opacity"; from: 1; to: 0; duration: 200 }
    }
    popEnter: Transition {
        NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 200 }
    }
    popExit: Transition {
        NumberAnimation { property: "opacity"; from: 1; to: 0; duration: 200 }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

3. 监听页面切换

StackView {
    id: stackView
    anchors.fill: parent

    onCurrentItemChanged: {
        console.log("Current page changed to:", currentItem);
    }
}
1
2
3
4
5
6
7
8

# 3.7 页面声明周期

在 QML 中,页面的生命周期由组件的创建、加载、显示、隐藏和销毁等阶段组成。理解 QML 页面的生命周期对于管理资源、处理事件和优化性能非常重要。

# 3.7.1 组件创建和销毁

触发时机:当 QML 文件被加载或实例化时。相关信号和函数:

  • Component.onCompleted:在组件完全初始化并准备好后触发。
  • Component.onDestruction:在组件即将被销毁时触发。
Rectangle {
   width: 100
   height: 100
   color: "red"

   Component.onCompleted: {
       console.log("组件创建完成");
   }

   Component.onDestruction: {
       console.log("组件即将销毁");
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 3.7.2 页面加载

触发时机:当页面被加载到视图或窗口时。相关信号和函数:

  • Page.onStatusChanged:当页面的状态发生变化时触发(如加载、显示、隐藏等)。
  • Loader.onLoaded:当使用 Loader 动态加载组件时触发。

示例:

Page {
   onStatusChanged: {
       if (status === Page.Active) {
           console.log("页面已激活");
       } else if (status === Page.Inactive) {
           console.log("页面已隐藏");
       }
   }
}
1
2
3
4
5
6
7
8
9

使用场景:

  1. 页面加载状态:在页面加载完成或状态变化时执行操作。
  2. 异步操作状态:在异步操作(如网络请求)状态变化时更新 UI。
  3. 窗口状态:在窗口状态(如最小化、最大化、全屏)变化时执行操作。

# 3.7.3 页面显示

触发时机:当页面变为可见时。相关信号和函数:

  • Item.visibleChanged:当 visible 属性发生变化时触发。
  • Window.onVisibleChanged:当窗口的可见性发生变化时触发。

示例:

Item {
   visible: true

   onVisibleChanged: {
       if (visible) {
           console.log("页面可见");
       } else {
           console.log("页面隐藏");
       }
   }
}
1
2
3
4
5
6
7
8
9
10
11

使用场景

  1. 动态显示/隐藏组件:当某个组件的可见性发生变化时,执行特定操作。当 rect.visible 从 false 变为 true 时,会触发 onVisibleChanged。
  2. 页面切换:在页面显示或隐藏时执行初始化或清理操作。
  3. 动画控制:在组件显示或隐藏时启动或停止动画。

# 3.7.4 页面激活

触发时机:当页面成为当前活动页面时(例如在 StackView 或 TabView 中切换页面)。

相关信号和函数:Page.onActivated:当页面被激活时触发。Page.onDeactivated:当页面被停用时触发。

示例:

Page {
   onActivated: {
       console.log("页面已激活");
   }

   onDeactivated: {
       console.log("页面已停用");
   }
}
1
2
3
4
5
6
7
8
9

# 3.7.5 页面销毁

触发时机:当页面被销毁或从内存中移除时。

相关信号和函数:Component.onDestruction:在组件即将销毁时触发。Loader.onItemRemoved:当使用 Loader 动态移除组件时触发。

示例:

Rectangle {
   width: 100
   height: 100
   color: "blue"

   Component.onDestruction: {
       console.log("组件即将销毁");
   }
}
1
2
3
4
5
6
7
8
9

# 3.7.6 动态加载和卸载

触发时机:当使用 Loader 动态加载或卸载组件时。相关信号和函数:

  • Loader.onLoaded:当组件加载完成时触发。
  • Loader.onItemRemoved:当组件被移除时触发。
Loader {
   id: loader
   source: "MyComponent.qml"

   onLoaded: {
       console.log("组件加载完成");
   }

   onItemRemoved: {
       console.log("组件已移除");
   }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 3.7.7 窗口生命周期

触发时机:当窗口被创建、显示、隐藏或关闭时。相关信号和函数:

  • Window.onVisibleChanged:当窗口的可见性发生变化时触发。
  • Window.onClosing:当窗口即将关闭时触发。
Window {
   visible: true

   onVisibleChanged: {
       if (visible) {
           console.log("窗口可见");
       } else {
           console.log("窗口隐藏");
       }
   }

   onClosing: {
       console.log("窗口即将关闭");
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 3.7.8 状态管理

触发时机:当组件的状态发生变化时。相关信号和函数:

  • State.onCompleted:当状态完全应用时触发。
  • State.onExited:当状态退出时触发。
Rectangle {
   width: 100
   height: 100
   color: "green"

   states: [
       State {
           name: "active"
           PropertyChanges { target: parent; color: "red" }
           onCompleted: console.log("状态已应用");
           onExited: console.log("状态已退出");
       }
   ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 3.7.9 生命周期总结

QML 页面的生命周期包括以下主要阶段:

  1. 组件创建:Component.onCompleted 和 Component.onDestruction。
  2. 页面加载:Page.onStatusChanged 和 Loader.onLoaded。
  3. 页面显示:Item.visibleChanged 和 Window.onVisibleChanged。
  4. 页面激活:Page.onActivated 和 Page.onDeactivated。
  5. 页面销毁:Component.onDestruction 和 Loader.onItemRemoved。
  6. 动态加载和卸载:Loader.onLoaded 和 Loader.onItemRemoved。
  7. 窗口生命周期:Window.onVisibleChanged 和 Window.onClosing。
  8. 状态管理:State.onCompleted 和 State.onExited。

# 3.8 异步编程技巧

在 Qt Quick 和 QML 中,异步编程是处理耗时操作(如网络请求、文件 I/O、复杂计算等)的关键技术,以避免阻塞 UI 线程,保持界面的流畅性。以下是 Qt Quick/QML 中实现异步编程的常见方法:

# 3.8.1 WorkerScript

WorkerScript 是 QML 中用于在后台线程中执行 JavaScript 代码的组件。它通过消息传递机制与主线程通信。示例:

import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 400
    height: 300

    Button {
        text: "开始任务"
        onClicked: worker.sendMessage({ action: "start" })
    }

    Text {
        id: resultText
        anchors.centerIn: parent
        text: "等待结果..."
    }

    WorkerScript {
        id: worker
        source: "worker.js"

        onMessage: {
            resultText.text = messageData.result;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

worker.js:

WorkerScript.onMessage = function(message) {
    if (message.action === "start") {
        // 模拟耗时操作
        var result = 0;
        for (var i = 0; i < 1000000000; i++) {
            result += i;
        }
        // 将结果发送回主线程
        WorkerScript.sendMessage({ result: "计算完成: " + result });
    }
};
1
2
3
4
5
6
7
8
9
10
11

# 3.8.2 Timer定时器

定时器(Timer) 是一种用于执行周期性任务或延迟任务的组件。它可以在指定的时间间隔内触发事件,非常适合用于动画、轮播、数据刷新等场景。

Timer {
   id: periodicTimer
   interval: 1000 // 定时器的时间间隔,1 秒
   repeat: true    //是否重复触发定时器
   running: true   //定时器是否正在运行
   onTriggered: {
      // 模拟耗时操作
      var result = 0;
      for (var i = 0; i < 100000000; i++) {
          result += i;
      }
      resultText.text = "计算完成: " + result;
   }
}

Button {
   text: "Start Delayed Task"
   onClicked: {
       delayedTimer.start();   //开始启动定时器
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

定时器的核心属性

  1. interval: 定时器的时间间隔,单位为毫秒(ms)。例如,interval: 1000 表示每隔 1 秒触发一次。
  2. repeat:是否重复触发定时器。如果为 true,定时器会按照 interval 重复触发;如果为 false,定时器只会触发一次。
  3. running:定时器是否正在运行。如果为 true,定时器会立即启动;如果为 false,定时器会停止。
  4. triggeredOnStart:定时器启动时是否立即触发一次。如果为 true,定时器启动时会立即触发一次,然后按照 interval 重复触发。

定时器的常用方法

  1. start(): 启动定时器。
  2. stop(): 停止定时器。
  3. restart():重启定时器。

定时器的注意事项

  1. 性能优化: 对于高频率的定时器(如动画),确保任务执行时间短,避免卡顿。
  2. 定时器冲突: 避免多个定时器同时运行,导致资源竞争。
  3. 定时器精度:定时器的触发时间可能受系统负载影响,无法保证完全精确。
  4. 定时器生命周期:确保定时器在组件销毁时停止,避免内存泄漏。

# 3.8.3 Qt.callLater

Qt.callLater 是 Qt/QML 提供的一个全局函数,用于将指定的函数推迟到当前事件循环结束后执行。

它的主要用途是避免在 UI 更新或事件处理过程中直接执行某些操作,从而防止潜在的竞争条件或 UI 卡顿。

为什么需要 Qt.callLater?

  • 避免 UI 卡顿:如果直接调用 passwordDialog.close(),可能会在当前事件循环中立即执行,导致 UI 更新不及时或卡顿。
  • 解决竞争条件:在某些情况下,直接执行操作可能会导致未定义的行为(例如,在 UI 更新过程中关闭对话框)。
  • 确保操作顺序:Qt.callLater 可以确保某些操作在特定事件(如 UI 更新)完成后执行。
import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 400
    height: 300

    Button {
        text: "开始任务"
        onClicked: {
            // 模拟耗时操作
            var result = 0;
            for (var i = 0; i < 100000000; i++) {
                result += i;
            }
            // 延迟更新 UI
            Qt.callLater(function() {
                resultText.text = "计算完成: " + result;
            });
        }
    }

    Text {
        id: resultText
        anchors.centerIn: parent
        text: "等待结果..."
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 3.8.4 C++和QML结合

对于更复杂的异步操作(如网络请求、文件 I/O),可以在 C++ 中实现异步逻辑,然后通过 QML 调用。示例:

C++ 部分:

#include <QObject>
#include <QTimer>
#include <QDebug>

class AsyncWorker : public QObject {
    Q_OBJECT
public:
    AsyncWorker(QObject *parent = nullptr) : QObject(parent) {}

    Q_INVOKABLE void startTask() {
        QTimer::singleShot(2000, this, [this]() {
            qDebug() << "任务完成";
            emit taskCompleted("结果数据");
        });
    }

signals:
    void taskCompleted(const QString &result);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

QML 部分:

import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 400
    height: 300

    Button {
        text: "开始任务"
        onClicked: worker.startTask()
    }

    Text {
        id: resultText
        anchors.centerIn: parent
        text: "等待结果..."
    }

    AsyncWorker {
        id: worker
        onTaskCompleted: {
            resultText.text = result;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 3.8.5 JavaScript异步

虽然 QML 本身不支持 Promise 和 async/await,但可以通过 JavaScript 的异步特性模拟类似行为。示例:

import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 400
    height: 300

    Button {
        text: "开始任务"
        onClicked: {
            asyncTask().then(function(result) {
                resultText.text = result;
            });
        }
    }

    Text {
        id: resultText
        anchors.centerIn: parent
        text: "等待结果..."
    }

    function asyncTask() {
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                resolve("任务完成");
            }, 2000);
        });
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 3.8.6 异步编程总结

在 Qt Quick/QML 中,实现异步编程的常见方法包括:

  1. WorkerScript:在后台线程中执行 JavaScript 代码。
  2. Timer:延迟执行任务或将任务分解为多个步骤。
  3. Qt.callLater:将函数推迟到当前事件循环结束后执行。
  4. C++ 和 QML 结合:在 C++ 中实现异步逻辑,通过 QML 调用。
  5. Promise 和 async/await:模拟 JavaScript 的异步特性。
  6. Loader 和 Component:动态加载和卸载组件。
上次更新: 2026/06/10, 11:13:41
Qml控件介绍
Canvas绘制

← Qml控件介绍 Canvas绘制→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式