QML开发:QML中的基本元素

发布于:2025-08-07 ⋅ 阅读:(20) ⋅ 点赞:(0)

一、概述

  在 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 对比:
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到