跳转到内容
新建笔记

Qt Quick 元素:控件、模型、动画、路径与模块边界

QML 是语言,Qt Quick、Qt Quick Controls、Qt Multimedia 等才是提供具体类型的模块。找到一个名称后,应同时确认它来自哪个模块、当前 Qt 版本是否提供、能否直接实例化,以及需要什么运行环境。本文以 Qt 6.10 为基准,保留基础类型、交互、布局、模型、动画、路径、媒体和扩展模块的查找入口。

先阅读 QML 语法与属性。下列每个 QML 代码块都是一个独立文件;除特别说明的图表程序外,可由 Qt Quick 应用或安装了相应模块的 qml 工具加载。示例使用无版本号导入,要求环境满足本文版本,不代表能够原样运行在 Qt 5。

基础显示、输入与控件

跳转到“基础显示、输入与控件”
名称模块与用途使用要点
RectangleQtQuick,矩形背景、边框、圆角color、border、radius 控制外观;它仍是一个矩形 Item
TextQtQuick,文本显示显式选择纯文本或富文本,注意换行、裁剪和字体大小
ImageQtQuick,图像显示source 是 URL;用 fillMode 控制缩放,检查 status 和资源路径
GradientQtQuick,渐变描述与 GradientStop 配合,赋给 Rectangle.gradient 等接受它的属性
LabelQtQuick.Controls,带控件样式的文本需要与其他 Controls 保持样式一致时使用
ButtonQtQuick.Controls,触发动作常用 text、icon、onClicked;也可定制 contentItem
CheckBox、SwitchQtQuick.Controls,选中状态或开关读写 checked;多选与开关在交互语义上有区别
RadioButtonQtQuick.Controls,互斥选项同一父项下默认自动互斥,也可用 ButtonGroup 显式分组
SliderQtQuick.Controls,范围内连续/步进选值from、to、value、stepSize;属性通知不带通用的 value 参数
SpinBoxQtQuick.Controls,整数步进输入用 from、to、value;小数显示需另行转换,并非直接声明任意浮点范围
ComboBoxQtQuick.Controls,从模型中选择model、currentIndex、currentText,复杂模型还要指定角色
ProgressBarQtQuick.Controls,进度反馈from、to、value;未知总量时使用 indeterminate
TextField、TextAreaQtQuick.Controls,单行/多行编辑根据需要设置校验器、占位文字、回显模式和滚动容器
MouseAreaQtQuick,鼠标按下、移动、点击、拖动用显式事件参数,如 onClicked: (mouse) => { ... }
MultiPointTouchAreaQtQuick,处理多个触点提供触点列表;需要缩放/拖动时也可选 PinchHandler、DragHandler
DropAreaQtQuick,接收拖放与 Drag 附加属性或平台拖放配合;不会自动生成拖动源
FocusScopeQtQuick,组合组件内部焦点域自身不绘制焦点边框;焦点项可用 activeFocus 决定外观
KeyEventQtQuick,键盘处理器收到的事件对象从 Keys.onPressed 的参数读取 key、text、accepted,不能当普通可视类型创建

以下 ControlsDemo.qml 把点击、动态输入、单选、多选、开关、数值联动、进度和键盘焦点放在一个完整页面。将焦点移到输入框后,方向键和文本输入由控件处理;空白焦点域收到空格时增加计数。

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQml.Models
FocusScope {
id: root
width: 560; height: 520
focus: true
property int clicks: 0
Keys.onPressed: (event) => {
if (event.key === Qt.Key_Space) {
clicks += 1
event.accepted = true
}
}
Rectangle {
anchors.fill: parent
color: "#f4f6f8"
border.color: root.activeFocus ? "steelblue" : "lightgray"
}
ColumnLayout {
anchors.fill: parent; anchors.margins: 16
spacing: 8
Label { id: counter; text: "点击/空格次数:" + root.clicks }
RowLayout {
Button { text: "增加"; onClicked: root.clicks += 1 }
CheckBox { id: enabledChoice; text: "允许编辑"; checked: true }
Switch { id: mode; text: "夜间模式" }
}
RowLayout {
RadioButton { id: localChoice; text: "本地"; checked: true }
RadioButton { id: remoteChoice; text: "远程" }
ComboBox {
id: formats
textRole: "name"
model: ListModel {
ListElement { name: "文本" }
ListElement { name: "图像" }
ListElement { name: "音频" }
}
delegate: ItemDelegate {
required property string name
width: formats.width
text: name
}
}
}
TextField {
id: titleInput
Layout.fillWidth: true
enabled: enabledChoice.checked
placeholderText: "输入标题"
}
TextArea {
id: bodyInput
Layout.fillWidth: true; Layout.fillHeight: true
enabled: enabledChoice.checked
placeholderText: "输入多行内容"
wrapMode: TextEdit.Wrap
}
RowLayout {
Slider { id: slider; Layout.fillWidth: true; from: 0; to: 100; value: 25 }
SpinBox { id: amount; from: 0; to: 100; value: 25 }
}
ProgressBar { id: progress; Layout.fillWidth: true; from: 0; to: 100; value: slider.value }
Rectangle {
id: tile
Layout.preferredWidth: 120; Layout.preferredHeight: 44
radius: 8; color: "lightblue"
Text { anchors.centerIn: parent; text: "点击色块" }
MouseArea {
anchors.fill: parent
onClicked: (mouse) => {
root.clicks += 1
tile.color = mouse.button === Qt.LeftButton ? "lightgreen" : "lightblue"
}
}
}
}
}

Slider 的通知处理、动态监听和取消监听详见 Connections。控件文本的自动转换不代表所有属性类型都可任意混用;不兼容赋值会产生诊断。

ComboBox 使用带 name 角色的 ListModel 时,textRole 决定选中项显示文字,delegate 决定弹出列表外观。用 ItemDelegate 可以保留菜单项点击和可访问性语义;仅把普通 Item/Rectangle 当委托,需要自行补齐相应交互。

DragDropDemo.qml 展示拖动源与接收区。释放鼠标由源 MouseArea 处理,并调用 Drag.drop();目标的完成信号是 DropArea.onDropped,不存在这里常被误写的 DropArea.onReleased。

import QtQuick
Item {
id: root
width: 460; height: 180
property int drops: 0
property string lastLabel: ""
Rectangle {
x: 260; y: 20; width: 160; height: 120
color: target.containsDrag ? "lightgreen" : "#e8edf2"
Text { anchors.centerIn: parent; text: "放到这里" }
DropArea {
id: target
anchors.fill: parent
keys: ["note"]
onDropped: (drop) => {
root.lastLabel = drop.source.label
root.drops += 1
drop.acceptProposedAction()
}
}
}
Rectangle {
id: card
x: 20; y: 20; width: 100; height: 60; color: "lightblue"
property string label: "笔记"
Drag.active: mouse.drag.active
Drag.source: card
Drag.keys: ["note"]
Drag.hotSpot.x: width / 2
Drag.hotSpot.y: height / 2
Text { anchors.centerIn: parent; text: card.label }
MouseArea {
id: mouse
anchors.fill: parent
drag.target: card
onReleased: card.Drag.drop()
}
}
}

位置排列、尺寸布局与页面切换

跳转到“位置排列、尺寸布局与页面切换”
名称模块与用途边界
Row、Column、GridQtQuick,按子项既有尺寸排列位置主要安排位置,不会因为父项变大就自动把每个子项拉伸
RowLayout、ColumnLayoutQtQuick.Layouts,水平/垂直分配空间用 Layout.minimumWidth、preferredWidth、fillWidth 等声明尺寸要求
GridLayoutQtQuick.Layouts,行列、跨行、跨列布局用 rowSpacing、columnSpacing;Layout.rowSpan、columnSpan 控制跨度
StackLayoutQtQuick.Layouts,显示一个现有子页面设置 currentIndex;不要假定 QML 中有 setCurrentIndex() 方法
StackViewQtQuick.Controls,页面栈导航push()、pop() 操作导航历史;与只切换既有子项的 StackLayout 用途不同
TabBarQtQuick.Controls,标签选择搭配 TabButton 和 StackLayout.currentIndex
ToolBarQtQuick.Controls,工具栏容器将按钮和布局放入其内容区域

布局应决定其直接子项的几何尺寸,避免又给这些子项设置互相竞争的 anchors、x/y、width/height 绑定。外层布局自己可以锚定父项。ColumnLayout.layoutDirection 控制水平方向相关排列/对齐,不会把垂直顺序倒过来;需要倒序时调整模型或子项顺序。锚点规则详见 锚点与边距。

LayoutNavigation.qml 展示标签页、行列尺寸约束、网格跨列、抽屉和一个独立页面栈。按“打开详情”会创建第二页,返回后销毁该导航实例;标签页则一直是 StackLayout 的两个子项。

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Item {
id: root
width: 640; height: 420
ColumnLayout {
anchors.fill: parent
ToolBar {
Layout.fillWidth: true
RowLayout {
Button { text: "导航"; onClicked: drawer.open() }
Label { text: "布局与页面" }
}
}
TabBar {
id: tabs
Layout.fillWidth: true
TabButton { text: "表单" }
TabButton { text: "页面栈" }
}
StackLayout {
id: pages
Layout.fillWidth: true; Layout.fillHeight: true
currentIndex: tabs.currentIndex
ColumnLayout {
RowLayout {
Rectangle { color: "lightblue"; Layout.preferredWidth: 100; Layout.preferredHeight: 40 }
Rectangle { color: "lightgreen"; Layout.fillWidth: true; Layout.preferredHeight: 40 }
}
GridLayout {
id: grid
columns: 2; rowSpacing: 8; columnSpacing: 12
Label { text: "姓名" }
TextField { Layout.fillWidth: true; placeholderText: "输入姓名" }
Label { text: "城市" }
TextField { Layout.fillWidth: true; placeholderText: "输入城市" }
Label { text: "此行横跨两列"; Layout.columnSpan: 2 }
}
Item { Layout.fillHeight: true }
}
StackView {
id: stack
initialItem: Component {
Button { text: "打开详情"; onClicked: stack.push(detailPage) }
}
}
}
}
Component {
id: detailPage
Button { text: "返回"; onClicked: stack.pop() }
}
Drawer {
id: drawer
width: 180; height: root.height
Column {
spacing: 8
Label { text: "导航目录" }
Button { text: "表单"; onClicked: { tabs.currentIndex = 0; drawer.close() } }
}
}
}

模型、视图、重复项与延迟加载

跳转到“模型、视图、重复项与延迟加载”
名称模块与用途关键区别
ListModelQtQml.Models,带角色的 QML 列表数据ListElement 声明初始项;append、setProperty、remove 等更新数据
ListView、GridViewQtQuick,列表/网格形式显示模型由 delegate 生成可视项;视口之外的实例由视图管理,不应靠 delegate 保存业务数据
RepeaterQtQuick,为模型每项创建可视对象通常搭配 Row/Column/Grid;它会创建所有委托,不具备 ListView 的按需实例化特点
LoaderQtQuick,按需创建组件使用 source 或 sourceComponent;通过 active 释放/重建对象,读取 item 前检查状态
TimerQtQml,事件循环中的定时触发interval、repeat、running 和 onTriggered;不是高精度实时调度器
TextMetricsQtQuick,计算指定字体下的文本尺寸设置与目标文字一致的 text、font,再读 width、height 等度量

ModelUtilities.qml 的两个视图共享一个模型;定时器只触发一次。Loader 创建的文本和度量对象读同一标题。委托中的 required property 明确列出视图需要注入的角色。

import QtQuick
import QtQml.Models
Item {
id: root
width: 520; height: 320
property string title: "模型与视图"
property bool showDetails: true
property int ticks: 0
ListModel {
id: entries
ListElement { name: "Alice"; value: 10 }
ListElement { name: "Bob"; value: 20 }
}
ListView {
id: list
x: 12; y: 12; width: 220; height: 130
model: entries
delegate: Text {
required property string name
required property int value
width: ListView.view.width; height: 30
text: name + ": " + value
}
}
GridView {
id: grid
x: 260; y: 12; width: 240; height: 130
cellWidth: 110; cellHeight: 50
model: entries
delegate: Rectangle {
required property string name
width: 100; height: 40; color: "lightblue"
Text { anchors.centerIn: parent; text: parent.name }
}
}
Row {
id: repeatedRow
x: 12; y: 160; spacing: 8
Repeater {
id: repeated
model: 3
Rectangle { width: 30; height: 30; color: "coral" }
}
}
TextMetrics { id: metrics; text: root.title; font.pixelSize: 18 }
Loader {
id: details
x: 12; y: 220
active: root.showDetails
sourceComponent: Component {
Text { text: root.title; font.pixelSize: 18 }
}
}
Timer { id: once; interval: 30; running: true; repeat: false; onTriggered: root.ticks += 1 }
}

需要在委托内部访问 ListView.isCurrentItem 等附加属性时,应明确附加对象所属的 delegate 根项,参见 附加属性与生命周期。

菜单、弹窗和系统选择器

跳转到“菜单、弹窗和系统选择器”
名称模块与用途使用方式
Menu、MenuItemQtQuick.Controls,菜单及动作项Menu.popup() 弹出;菜单项通过 onTriggered 处理动作
ContextMenuQtQuick.Controls,自 Qt 6.9 提供的附加类型使用 ContextMenu.menu: Menu { ... } 关联右键菜单,不能写成通用独立容器
PopupQtQuick.Controls,通用浮层通过 open/close 控制,并配置关闭策略、模态状态和内容
DialogQtQuick.Controls,含标题、内容及标准按钮的对话框使用 standardButtons、onAccepted、onRejected
FileDialog、ColorDialogQtQuick.Dialogs,文件/颜色选择Qt 6 文件结果为 selectedFile;目录选择用同模块的 FolderDialog

DialogsDemo.qml 展示菜单、确认框、文件、目录和颜色选择。系统对话框实际外观取决于平台;只有用户接受后才保存选择结果。URL 应作为 URL 交给媒体/图像 API,不能直接假定它是操作系统路径字符串。

import QtQuick
import QtQuick.Controls
import QtQuick.Dialogs as NativeDialogs
Item {
id: root
width: 460; height: 280
property url chosenFile: ""
property url chosenFolder: ""
property color chosenColor: "lightblue"
property int acceptedCount: 0
Column {
spacing: 8
Button {
text: "右键菜单 / 点击选择文件"
onClicked: fileDialog.open()
ContextMenu.menu: Menu {
MenuItem { text: "选择目录"; onTriggered: folderDialog.open() }
MenuItem { text: "选择颜色"; onTriggered: colorDialog.open() }
}
}
Button { text: "确认"; onClicked: confirm.open() }
Button { text: "提示浮层"; onClicked: tip.open() }
Rectangle { width: 80; height: 40; color: root.chosenColor }
}
Dialog {
id: confirm
title: "保存更改"
standardButtons: Dialog.Ok | Dialog.Cancel
onAccepted: root.acceptedCount += 1
Label { text: "是否保存当前内容?" }
}
Popup { id: tip; width: 150; height: 70; Label { text: "操作提示" } }
NativeDialogs.FileDialog {
id: fileDialog
title: "选择一个文件"
fileMode: NativeDialogs.FileDialog.OpenFile
onAccepted: root.chosenFile = selectedFile
}
NativeDialogs.FolderDialog { id: folderDialog; onAccepted: root.chosenFolder = selectedFolder }
NativeDialogs.ColorDialog { id: colorDialog; onAccepted: root.chosenColor = selectedColor }
}

ContextMenu 的附加用法和引入版本见 Qt 6.10 ContextMenu 文档。

动画、行为、状态与过渡

跳转到“动画、行为、状态与过渡”
名称作用典型参数或边界
Animation所有动画共享的抽象基类接口running、paused、loops、启动停止方法;本身不可直接创建
PropertyAnimation对指定属性执行插值动画target、property、from、to、duration、easing
NumberAnimation数值属性变化位置、尺寸、透明度等;透明度的属性名是 opacity
ColorAnimation颜色变化指定颜色属性和目标色
RotationAnimation角度变化direction 可选最短路径或特定旋转方向
SequentialAnimation子动画依次运行内部放动画,不要把 Rectangle 放入动画序列
ParallelAnimation子动画同时运行可嵌入序列,组合位移、颜色和旋转
PauseAnimation给动画序列插入等待duration 为等待时间,不会阻塞整个应用线程
Behavior属性变化时使用默认动画如 Behavior on x;写入新值是触发条件
SmoothedAnimation在新目标值到来时平滑追踪常用 velocity;适合连续更新的目标
SpringAnimation以弹簧方式趋近目标spring、damping 等控制响应;不等同于固定时长匀速移动
PathAnimation沿路径改变目标位置path、target、duration、定向设置;没有通用 yoyo 属性
State描述界面的命名配置用 PropertyChanges 等声明目标值,由 Item 的 state 选择
Transition在状态之间执行动画from、to 和子动画;状态属性不是 State.active

三种启动方式要分清:独立动画通常显式 start()/restart() 或设 running;NumberAnimation on x 这种属性值来源默认会运行;Behavior on x 则在 x 的目标值改变时响应。loops: Animation.Infinite 表示无限循环,反向往返可用两个方向的动画组成序列,不能凭空增加 yoyo。参见 Qt Quick 动画与过渡。

AnimationsDemo.qml 的 startAll() 同时启动四组独立示范:序列内并行变化、平滑追踪、弹簧追踪和三角形路径;另一色块通过状态切换宽度和透明度。

import QtQuick
Item {
id: root
width: 440; height: 350
property real goal: 20
function startAll() {
movement.restart()
goal = 200
travel.restart()
stateBox.state = "expanded"
}
Rectangle { id: box; x: 20; y: 20; width: 32; height: 32; color: "red" }
SequentialAnimation {
id: movement
ParallelAnimation {
NumberAnimation { target: box; property: "x"; to: 200; duration: 120 }
ColorAnimation { target: box; property: "color"; to: "blue"; duration: 120 }
RotationAnimation { target: box; property: "rotation"; to: 180; duration: 120; direction: RotationAnimation.Shortest }
}
PauseAnimation { duration: 30 }
PropertyAnimation { target: box; property: "opacity"; to: 0.5; duration: 80 }
}
Rectangle {
id: smooth
x: root.goal; y: 85; width: 32; height: 32; color: "orange"
Behavior on x { SmoothedAnimation { velocity: 800 } }
}
Rectangle {
id: springBox
x: root.goal; y: 145; width: 32; height: 32; color: "green"
Behavior on x { SpringAnimation { spring: 3; damping: 0.3; epsilon: 0.05 } }
}
Rectangle { id: runner; x: 20; y: 220; width: 16; height: 16; radius: 8; color: "purple" }
PathAnimation {
id: travel
target: runner; duration: 360
path: Path {
startX: 20; startY: 220
PathLine { x: 180; y: 220 }
PathLine { x: 100; y: 300 }
PathLine { x: 20; y: 220 }
}
}
Rectangle {
id: stateBox
x: 260; y: 220; width: 60; height: 50; color: "steelblue"
states: State {
name: "expanded"
PropertyChanges { target: stateBox; width: 140; opacity: 0.6 }
}
transitions: Transition {
from: ""; to: "expanded"
NumberAnimation { properties: "width,opacity"; duration: 180 }
}
}
MouseArea { anchors.fill: parent; onClicked: root.startAll() }
}

频繁变化的目标适合 SmoothedAnimation/SpringAnimation;需要确定时长和终点的 UI 转场适合 NumberAnimation。动画更新跟随事件循环与帧调度,不保证每毫秒都产生一次可见帧。

还可以在运行时创建动画,但固定动画优先声明在 QML 中,避免每次点击都解析字符串。下面 DynamicAnimation.qml 保留 Qt.createQmlObject() 的动态创建方式,显式指定 target,并在停止后销毁临时动画。重复点击会先停止旧动画;动画不会永远积累在父对象下。动态字符串应来自受控代码,不应直接拼接不可信输入。

import QtQuick
Item {
id: root
width: 300; height: 180
property var animation: null
function animateWidth() {
if (animation !== null)
animation.stop()
const created = Qt.createQmlObject(
'import QtQuick; NumberAnimation { property: "width"; to: 200; duration: 120 }',
box, "width-animation")
created.target = box
animation = created
created.stopped.connect(function() {
if (root.animation === created)
root.animation = null
created.destroy()
})
created.start()
}
Rectangle {
id: box
width: 100; height: 100; color: "lightblue"
MouseArea { anchors.fill: parent; onClicked: root.animateWidth() }
}
}

路径、形状、渐变与视觉效果

跳转到“路径、形状、渐变与视觉效果”
名称模块与作用正确关系
ShapeQtQuick.Shapes,绘制一个或多个形状路径继承 Item,能够使用 anchors
ShapePathQtQuick.Shapes,路径及描边/填充样式继承 Path,直接放路径段;没有再套一层 path: Path {} 的属性
PathQtQuick,声明路径数据供 PathAnimation、PathView、ShapePath 等使用;自身不直接绘制
PathLineQtQuick,直线段从当前位置连到 x,y
PathQuadQtQuick,二次贝塞尔曲线一个控制点 controlX,controlY 和终点
PathCubicQtQuick,三次贝塞尔曲线两个控制点及终点
PathCurveQtQuick,经过一组点的 Catmull–Rom 曲线不是 PathCubic 的别名;连续段形成平滑曲线
PathArcQtQuick,椭圆弧段radiusX,radiusY、方向和终点;半径必须与目标弧段几何相容
PathSvgQtQuick,解析 SVG path 数据字符串path 是字符串;跨代码行时用字符串拼接,不能在普通引号内直接换行
LinearGradient、RadialGradientQtQuick.Shapes,ShapePath 的填充渐变赋给 fillGradient;与 Qt5Compat.GraphicalEffects 中同名类型不是同一个 API
ShaderEffectQtQuick,用着色器绘制效果Qt 6 的着色器通常用 Shader Tools 预编译为 .qsb,不是直接套用 Qt 5 内联 GLSL 字符串

ShapesDemo.qml 把直线、二次/三次曲线、插值曲线、圆弧和 SVG 路径放在完整的 Shape 中。第一条路径显式回到起点形成封闭轮廓;圆弧两端相距 100,radiusX、radiusY 均为 50。ShapePath 的声明式路径段与 QPainterPath/Canvas 的 moveTo()、lineTo() 方法属于不同 API,不能相互照抄。

import QtQuick
import QtQuick.Shapes
Item {
id: root
width: 420; height: 300
Shape {
id: shapes
anchors.fill: parent
ShapePath {
id: outline
strokeColor: "navy"; strokeWidth: 2
fillGradient: LinearGradient {
x1: 20; y1: 20; x2: 180; y2: 130
GradientStop { position: 0; color: "lightblue" }
GradientStop { position: 1; color: "white" }
}
startX: 20; startY: 20
PathLine { x: 180; y: 20 }
PathQuad { x: 180; y: 100; controlX: 230; controlY: 60 }
PathCubic { x: 20; y: 100; control1X: 150; control1Y: 160; control2X: 50; control2Y: 40 }
PathLine { x: 20; y: 20 }
}
ShapePath {
id: arc
strokeColor: "crimson"; strokeWidth: 3; fillColor: "transparent"
startX: 260; startY: 20
PathArc { x: 360; y: 20; radiusX: 50; radiusY: 50; direction: PathArc.Clockwise }
}
ShapePath {
id: curve
strokeColor: "green"; strokeWidth: 3; fillColor: "transparent"
startX: 20; startY: 190
PathCurve { x: 70; y: 150 }
PathCurve { x: 130; y: 230 }
PathCurve { x: 200; y: 190 }
}
ShapePath {
id: svg
strokeColor: "purple"; strokeWidth: 2
fillGradient: RadialGradient {
centerX: 300; centerY: 200; centerRadius: 65
focalX: 300; focalY: 200
GradientStop { position: 0; color: "white" }
GradientStop { position: 1; color: "orchid" }
}
PathSvg { path: "M 250 170 L 350 170 " + "L 330 240 L 270 240 Z" }
}
}
}

Shape 并非在所有场景都比 Canvas 快;复杂度、路径更新频率、后端和缓存方式都会影响性能。几何对象成功加载,也不等于每种 GPU 后端都已验证画面。

模糊、颜色调整和阴影可考虑 QtQuick.Effects.MultiEffect,或在确需兼容旧效果时使用 Qt5Compat.GraphicalEffects。MultiEffect 的 source、blurEnabled、shadowEnabled 等按需开启;避免同时显示源与效果而意外叠画。阴影还涉及边界、裁剪和额外纹理尺寸,不能只改一个名称就保证效果相同。参见 MultiEffect 与 ShaderEffect。

名称Qt 6 中的作用必须区分的对象
MediaPlayer播放本地或网络媒体,控制播放、暂停、定位与状态用 audioOutput 连接 AudioOutput,用 videoOutput 连接 VideoOutput
VideoOutput显示视频帧Qt 6 应由 MediaPlayer 或 CaptureSession 向其输出,不使用 Qt 5 的 source: player 写法
VideoQtMultimedia 的便捷视频组件Qt 6.10 仍提供,组合了播放和显示功能,不应误判为已从 Qt 6 删除
SoundEffect适合短促反馈音的低延迟播放source、volume、loops;无限重复枚举为 SoundEffect.Infinite
CameraQtMultimedia 中的真实摄像设备控制通过 CaptureSession 连接 VideoOutput;权限、设备和后端支持另行处理
AudioQt 5 QtMultimedia 的旧接口Qt 6 使用 MediaPlayer + AudioOutput;音量设置在 AudioOutput 上

MediaDemo.qml 默认不访问文件、不启用摄像头。给 mediaUrl、clipUrl、effectUrl 赋可访问的 URL 后,再调用相应播放方法;用 camera.start() 启动采集前应完成平台摄像权限处理。示例中的三块输出分别属于通用播放器、便捷 Video 和摄像头采集。

import QtQuick
import QtMultimedia
Item {
id: root
width: 660; height: 240
property url mediaUrl: ""
property url clipUrl: ""
property url effectUrl: ""
function playMedia() { if (mediaUrl.toString().length > 0) player.play() }
function pauseMedia() { player.pause() }
function playClip() { if (clipUrl.toString().length > 0) video.play() }
function playEffect() { if (effectUrl.toString().length > 0) effect.play() }
AudioOutput { id: audio; volume: 0.5 }
MediaPlayer {
id: player
source: root.mediaUrl
audioOutput: audio
videoOutput: output
}
VideoOutput { id: output; x: 0; width: 210; height: 180; fillMode: VideoOutput.PreserveAspectFit }
Video {
id: video
x: 220; width: 210; height: 180
source: root.clipUrl
autoPlay: false
volume: 0.5
}
SoundEffect { id: effect; source: root.effectUrl; volume: 0.4; loops: SoundEffect.Infinite }
Camera { id: camera; active: false }
CaptureSession { id: capture; camera: camera; videoOutput: preview }
VideoOutput { id: preview; x: 440; width: 210; height: 180 }
}

视频长宽比由 VideoOutput/Video 的填充模式处理;音量的 0~1 取值是接口刻度,不应理解为感知响度线性。文件格式和编解码器能力取决于 Qt Multimedia 后端及系统环境,不能仅凭 .mp3、.wav、.mp4 后缀保证播放。生产程序还应处理 errorOccurred、媒体状态和加载进度,短音效应等待资源就绪。MediaPlayer/Video 的播放状态用 playbackState 及其变化通知判断,不应使用拼造的 status == Video.Playing;stop() 停止播放,播放器的 position/setPosition()、Video 的 seek() 等定位接口应按所属类型和 seekable 状态使用。这里验证的是对象、属性及输出连接,未声称真实媒体、音频硬件或摄像头已运行。参见 Qt 6 Multimedia 迁移 和 Video。

图表:先确认 Qt Charts 与 Qt Graphs

跳转到“图表:先确认 Qt Charts 与 Qt Graphs”

ChartView 属于 QtCharts;该模块的 LineSeries、PieSeries、BarSeries、ScatterSeries 分别用于折线、饼图、分组条形图和散点图。它们不是仅导入 QtQuick 后就能创建的通用类型。Qt Graphs 也有若干同名系列,但使用 GraphsView 等另一套接口,不能只替换 import 就保证兼容。

Qt Charts 自 Qt 6.10 起弃用,新项目应评估 Qt Graphs;维护旧项目时仍需正确识别 ChartView 的写法。下面的 ChartsDemo.qml 同时展示折线和带五个数据点的条形图,必须安装 Qt Charts,并使用以 QApplication 创建的宿主程序,而不只是 QGuiApplication。这与 Qt Charts 对 Graphics View 的依赖有关。Qt Charts 概览

import QtQuick
import QtCharts
Item {
id: root
width: 520; height: 640
ChartView {
id: chart
width: parent.width; height: 320
title: "温度趋势"
antialiasing: true
ValueAxis { id: axisX; min: 0; max: 3; tickCount: 4 }
ValueAxis { id: axisY; min: 0; max: 30 }
LineSeries {
id: line
name: "温度"
axisX: axisX; axisY: axisY
XYPoint { x: 0; y: 12 }
XYPoint { x: 1; y: 18 }
XYPoint { x: 2; y: 16 }
XYPoint { x: 3; y: 25 }
}
}
ChartView {
id: barChart
y: 320; width: parent.width; height: 320
title: "分类数据"
BarSeries {
id: bars
axisX: BarCategoryAxis { categories: ["A", "B", "C", "D", "E"] }
BarSet { id: set; label: "Set 1"; values: [1, 2, 3, 4, 5] }
}
}
}

地图:提供者与网络是额外依赖

跳转到“地图:提供者与网络是额外依赖”

Map 来自 QtLocation,QtPositioning 提供坐标。地图插件决定瓦片来源、支持能力和所需参数;网络、提供者服务及使用条件会影响显示。下面的 MapDemo.qml 将请求地图服务,适用于具备对应插件和网络的运行环境,不能把一个空白 Map 对象当作地图可用性证明。

import QtQuick
import QtLocation
import QtPositioning
Item {
id: root
width: 520; height: 320
Plugin { id: mapProvider; name: "osm" }
Map {
id: map
anchors.fill: parent
plugin: mapProvider
center: QtPositioning.coordinate(39.9, 116.4)
zoomLevel: 10
}
}

交互缩放、拖动需要另配输入处理器或使用包含所需交互的组件。不能因为设置了 center 和 zoomLevel 就假定全部鼠标操作已自动提供。Qt Location Map

3D:场景相机与硬件摄像头不同

跳转到“3D:场景相机与硬件摄像头不同”

Qt Quick 3D 通过 View3D 将场景放入 Qt Quick。QtQuick3D.Camera 与 Light 是不可直接创建的基类;实际创建 PerspectiveCamera/OrthographicCamera 和 DirectionalLight/PointLight/SpotLight。这与 QtMultimedia.Camera 采集真实设备视频完全不同,Qt3D.Render 也有自己的一组同名 API。

SceneDemo.qml 显示相机、方向光和内置立方体资源。Qt Quick 3D 的相机朝局部负 Z 方向看,下面把相机放在 z=400。需要朝向目标时可调用相机的 lookAt() 方法;不要写成不存在的 lookAt: Qt.vector3d(...) 属性赋值。

import QtQuick
import QtQuick3D
Item {
id: root
width: 480; height: 320
View3D {
id: scene
anchors.fill: parent
environment: SceneEnvironment {
backgroundMode: SceneEnvironment.Color
clearColor: "#e8edf2"
}
camera: camera
PerspectiveCamera { id: camera; z: 400 }
DirectionalLight { id: light; eulerRotation.x: -30; brightness: 1.2 }
Model {
id: cube
source: "#Cube"
eulerRotation: Qt.vector3d(20, 35, 0)
materials: PrincipledMaterial { baseColor: "steelblue" }
}
}
}

Qt Quick 3D 需要合适的图形后端;仅创建场景对象不证明 GPU 渲染成功。Qt Quick 3D QML 类型

容易混淆的旧名称和非通用名称

跳转到“容易混淆的旧名称和非通用名称”

以下名称保留为查找入口,但不能假定它们是 Qt 6.10 常用模块中同名且可直接创建的 QML 类型。项目可以定义自己的同名组件,因此诊断“不是一个类型”时还应检查项目 QML 模块和导入路径。

名称应如何理解或替换
Circle、Ellipse圆可由正方形 Rectangle 设置 radius 绘制;椭圆用 Shape 的弧段、SVG 或 Canvas,不能把不等宽高的圆角矩形一概称作椭圆
Line、Polygon、Arc用 ShapePath + PathLine/PathArc 等描述几何;QtQuick 没有这里假定的通用同名可视类型
Opacity普通 Qt Quick Item 使用小写 opacity 属性,透明度动画用 NumberAnimation
GestureArea不应视作 QtQuick 的通用手势类型;按需求选择 TapHandler、DragHandler、PinchHandler 或 MultiPointTouchArea
DragArea拖动可用 DragHandler 或 MouseArea.drag;跨区域拖放用 Drag 附加属性 + DropArea
FocusArea、FocusHandler不是此处假定的标准焦点组件;使用 focus、activeFocus、FocusScope、Keys 和 focus/activeFocus 属性通知
FocusIndicator焦点外观通常是控件样式或自定义组件,用 activeFocus 绑定边框/可见性;不要依赖未导入的同名类型
ImageButton使用 Button.icon 或定制 Button.contentItem,也可自定义组件;不能只导入 QtQuick 就假定存在
ImageView、ImageViewer图像基本显示用 Image;缩放、滚动、预览器由 Flickable、输入处理器等组合
DatePicker、TimePicker、DateTimeEditQt Quick Controls 没有这里假定的三个通用控件;可用 CalendarModel/MonthGrid/DayOfWeekRow 等日期部件、Tumbler 或 SpinBox/TextField 组合,注意校验和时区;Qt Widgets 的 QDateTimeEdit 是另一套 API
GridModel、SimpleListModel普通列表/网格通常用 ListModel、JavaScript 数组或 C++ QAbstractItemModel;GridView 是视图,不要求一个名叫 GridModel 的类型
NavigationDrawerQt Quick Controls 的抽屉类型名是 Drawer,导航内容由应用组合
TabView常见于旧 Qt Quick Controls 1;Qt 6 Controls 用 TabBar + StackLayout 等组合
PopupMenu使用 Qt Quick Controls Menu;Popup 是更通用的浮层基础类型
DropShadowEffect、GraphicsEffect不要与 QWidget 的 QGraphicsEffect 类体系混用;Qt Quick 可用 MultiEffect,或兼容模块中的 DropShadow 等明确类型
ImageFilter不是此处假定的统一图像滤镜类型;按需求使用 MultiEffect、ShaderEffect、兼容图形效果或 C++ 图像处理
FileSelectorQt 的资源变体选择关联 C++ QQmlFileSelector/QFileSelector,不能把概念直接写成任意 FileSelector QML 对象
ImageProvider动态图像通常由 C++ QQuickImageProvider 注册到引擎,然后在 Image.source 使用 image:// URL;不是普通 QML ImageProvider 容器
Context3D不能将其视为 QtQuick 的通用 3D 场景入口;Qt Quick 3D 使用 View3D,旧 Canvas3D 等接口要按版本另查
Lens不应套用为 Qt Quick 3D 的通用实例类型;投影参数放在相应 PerspectiveCamera/OrthographicCamera 上,Qt 3D 的 CameraLens 属于另一模块
HeatMap不是这里列出的 QtCharts 通用图表类型;可按数据用着色矩形网格、图像或具体图表扩展实现,先确认库的真实类型与版本
SoundPlayerQtMultimedia 使用 MediaPlayer 或 SoundEffect;若项目提供同名封装,按该项目接口使用

查类型时先查 Qt 6.10 QML 类型总表,再进入具体模块文档;对于旧博客示例尤其要检查模块和版本。实例成功加载、属性行为正确、实际外部资源可用和最终画面正确是不同层次的验证。