驾驶舱
一个利用Graphs模拟飞机驾驶舱的示例应用程序。

该驾驶舱示例运用了多种不同的图类型来绘制虚构的飞机控制屏幕。示例中使用的图包括:
- PieSeries (速度表)
- LineSeries (振动面板、导航地图)
- AreaSeries (导航图、主飞行显示器)
- BarSeries (导航图、主飞行显示器)
- ScatterSeries (导航图)
- SplineSeries (主飞行显示器)
运行示例
您可以从以下位置运行示例:
- Qt Creator
打开Welcome 模式,并从Examples 中选择该示例。有关更多信息,请参阅Qt Creator :教程:构建和运行。
- Qt Extension for Visual Studio Code
在Command Palette 中运行Qt: Open Qt examples 命令,然后从列表中选择该示例。有关更多信息,请参阅Qt Extension for Visual Studio Code :教程:构建和运行。
速度计
速度表视图由单个GraphsView 中的 3 个PieSeries 组成,两个表盘的指针均由 QML Rectangles 实现。
GraphsTheme 的backgroundVisible属性设置为false 。所有PieSlices 都拥有各自的自定义颜色。为了显示中心为空心的圆形刻度盘,该示例使用了不同holeSize的PieSeries 。
GraphsView {
id: chart
anchors.fill: parent
anchors.margins: 20
theme: GraphsTheme {
backgroundVisible: false
borderColors: ["#252525"]
}
PieSeries {
id: pieOuter
pieSize: 1
holeSize: 0.8
startAngle: -120
endAngle: 120
PieSlice { label: "Stall"; value: 1; color: "#ff0000"; labelVisible: false }
PieSlice { label: "Optimal"; value: 4; color: "#00ff00"; labelVisible: false }
PieSlice { label: "Overspeed"; value: 1; color: "#ffaa22"; labelVisible: false }
}
PieSeries {
pieSize: 0.8
holeSize: 0.6
startAngle: -120
endAngle: 120
PieSlice { value: 1; color: "#ffffff"; }
PieSlice { value: 4; color: "#252525"; }
PieSlice { value: 1; color: "#ffffff"; }
PieSlice { value: 4; color: "#252525"; }
PieSlice { value: 1; color: "#ffffff"; }
PieSlice { value: 4; color: "#252525"; }
PieSlice { value: 1; color: "#ffffff"; }
PieSlice { value: 4; color: "#252525"; }
PieSlice { value: 1; color: "#ffffff"; }
PieSlice { value: 4; color: "#252525"; }
PieSlice { value: 1; color: "#ffffff"; }
PieSlice { value: 4; color: "#252525"; }
PieSlice { value: 1; color: "#ffffff"; }
PieSlice { value: 4; color: "#252525"; }
PieSlice { value: 1; color: "#ffffff"; }
PieSlice { value: 4; color: "#252525"; }
PieSlice { value: 1; color: "#ffffff"; }
PieSlice { value: 4; color: "#252525"; }
PieSlice { value: 1; color: "#ffffff"; }
}
PieSeries {
pieSize: 0.6
holeSize: 1.0
startAngle: -120
endAngle: 120
verticalPosition: 1
PieSlice { label: "Stall"; value: 1; color: "#ff0000"; labelVisible: false }
PieSlice { label: "Optimal"; value: 4; color: "#00ff00"; labelVisible: false }
PieSlice { label: "Overspeed"; value: 1; color: "#ffaa22"; labelVisible: false }
}
}振动面板
振动面板包含一个LineSeries ,该控件会在运行时动态更新。启动后,通过QML的invokedappend函数向该序列添加一组数据点。随后在每个帧中,使用replace函数将这些值替换为计算得出的新值。用户可以通过振动图表面板更改这些值。
LineSeries {
id: line
property int divisions: 500
property real amplitude: 0.5
property real resolution: 0.5
FrameAnimation {
running: true
onTriggered: {
for (let i = 0; i < line.divisions; ++i) {
let y = Math.sin(line.resolution*i)
y *= Math.cos(i)
y *= Math.sin(i / line.divisions * 3.2) * 3 * line.amplitude * Math.random()
line.replace(i, (i/line.divisions) * 8.0, y + 4)
}
}
}
Component.onCompleted: {
for (let i = 1; i <= divisions; ++i) {
append((i/divisions) * 8.0, 4.0)
}
}
function change(newDivs) {
let delta = newDivs - divisions
if (delta < 0) {
delta = Math.abs(delta)
removeMultiple(count - 1 - delta, delta)
} else {
for (let i = 0; i < delta; ++i) {
append(((count + i)/divisions) * 8.0, 4.0)
}
}
divisions = newDivs
}
}振动图表面板
该面板包含控制旋钮,用于调整影响“振动面板”中可视化效果的数值。
导航地图
导航地图包含两个主要部分:
- 左侧面板包含多个BarSeries ,其自定义着色器利用BarSets 的颜色为每根条形上色。
BarSeries { property real barOpacity: 0. id: barSeries barsType: BarSeries.BarsType.Stacked barWidth: 0.2 barDelegate: Item { id: delegate antialiasing: true property real barOpacity: 0.5 property color barColor property string barLabel FrameAnimation { running: true onTriggered: { delegate.barOpacity = Math.abs(Math.sin(elapsedTime)) } } ShaderEffect { id: effect readonly property alias iTime: delegate.barOpacity readonly property alias iColor: delegate.barColor readonly property vector3d iResolution: Qt.vector3d(width, height, 1.0) blending: true fragmentShader: 'bar.frag.qsb' anchors.fill: parent } } BarSet { id: set1; label: "Low"; values: [1, 2, 3, 1]; color: "red" } BarSet { id: set2; label: "Medium"; values: [2, 2, 0, 4]; color: "yellow"} BarSet { id: set3; label: "High"; values: [3, 2, 3, 1]; color: "green"} } - 右侧面板包含:
- 一个AreaSeries ,其中包含两个LineSeries ,用于可视化一个虚构的湖泊。
- 其上方的ScatterSeries 在地图上显示自定义图标,例如机场。
- “添加”(ADD)按钮会添加一个LineSeries ,其点可以移动以创建路径。该LineSeries 为pointDelegate使用了自定义着色器,而ScatterSeries 则使用了一张图片。
AreaSeries { property double x: 0 property double y: 0 id: lake1 color: "blue" upperSeries: LineSeries { id: s1 XYPoint { x: 0.0; y: -3.5 } XYPoint { x: 1.0; y: -5.0 } XYPoint { x: 2.0; y: -2.5 } XYPoint { x: 2.5; y: -4.0 } XYPoint { x: 3.0; y: -4.2 } } lowerSeries: LineSeries { id: s2 XYPoint { x: 0.0; y: -7.2 } XYPoint { x: 1.0; y: -7.0 } XYPoint { x: 2.0; y: -8.5 } XYPoint { x: 2.5; y: -8.0 } XYPoint { x: 3.0; y: -9.0 } XYPoint { x: 4.0; y: -6.5 } } } AreaSeries { property double x: 0 property double y: 0 id: lake2 color: "blue" upperSeries: LineSeries { id: s3 XYPoint { x: 0.0; y: 1.5 } XYPoint { x: 1.0; y: 3.0 } XYPoint { x: 2.0; y: 4.5 } XYPoint { x: 2.5; y: 4.8 } XYPoint { x: 3.0; y: 4.0 } } lowerSeries: LineSeries { id: s4 XYPoint { x: 0.0; y: 0.0 } XYPoint { x: 1.0; y: 0.5 } XYPoint { x: 2.0; y: 0.2 } XYPoint { x: 2.5; y: 1.5 } XYPoint { x: 3.0; y: 1.0 } XYPoint { x: 4.0; y: 0.6 } } } // POI ScatterSeries { name: "Airport" pointDelegate: Image { source: "airplane-ico.png" mipmap: true width: 30 height: 30 } XYPoint{x: 4.0; y: 5.7} XYPoint{x: 2.2; y: 8.2} XYPoint{x: 6.4; y: 1.2} XYPoint{x: 7.4; y: 7.8} } LineSeries { id: linePath selectable: true draggable: true color: "white" pointDelegate: Item { width: 50 height: 50 property real pointValueX property real pointValueY FrameAnimation { id: scatterAnim running: true } ShaderEffect { readonly property vector3d iResolution: Qt.vector3d(width, height, 1.0) readonly property alias iTime: scatterAnim.elapsedTime blending: true fragmentShader: 'circleMarker.frag.qsb' anchors.fill: parent } Text { color: "white" font.pointSize: 4 text: "LAT: " + pointValueX.toFixed(1) + ", " + "LON: " + pointValueY.toFixed(1) } } }
主飞行显示器
主飞行显示界面模拟了地形的“3D”视图。该界面通过两个AreaSeries 实现,分别用于呈现地面和天空,并各自采用自定义颜色。FrameAnimation 负责更新这些系列的数据值。
AreaSeries {
id: upperArea
color: "cyan"
upperSeries: LineSeries {
XYPoint {x: 0; y: 10}
XYPoint {x: 10; y: 10}
}
lowerSeries: LineSeries {
id: upperLine
XYPoint {x: 0; y: 3}
XYPoint {x: 10; y: 4}
}
}
FrameAnimation {
running: true
onTriggered: {
upperLine.replace(0, upperLine.at(0).x, Math.sin(elapsedTime) + 6)
upperLine.replace(1, upperLine.at(1).x, Math.cos(elapsedTime) + 6)
lowerLine.replace(0, lowerLine.at(0).x, Math.sin(elapsedTime) + 6)
lowerLine.replace(1, lowerLine.at(1).x, Math.cos(elapsedTime) + 6)
barSet.values = [Math.sin(elapsedTime) + 5]
}
}在左侧,一个主题化的BarSeries 显示y轴标签。该BarSeries 同样为条形使用了自定义着色器。
BarSeries {
id: barSeries
selectable: true
barDelegate: Item {
id: delegate
antialiasing: true
property real barOpacity: 0.5
property color barColor
property string barLabel
ShaderEffect {
id: effect
readonly property vector3d iResolution: Qt.vector3d(width, height, 1.0)
blending: true
fragmentShader: 'pitchbar.frag.qsb'
anchors.fill: parent
}
}
BarSet { id: barSet; values: []; selectedColor: "red" }
}视图底部,一个SplineSeries 可视化了飞机下方的地形高度。该SplineSeries 每帧都会更新。负责更新该系列的数据的代码会将一组连续的数据点追加到队列末尾,并从队列首部移除。鼠标悬停时,SplineSeries 会显示一个工具提示,其中显示 y 轴值(海拔)。
GraphsView {
anchors.fill: parent
anchors.leftMargin: -90
anchors.rightMargin: -80
anchors.bottomMargin: -30
theme: GraphsTheme {
backgroundVisible: false
plotAreaBackgroundColor: "#11000000"
}
axisX: ValueAxis {
max: 10
subTickCount: 9
lineVisible: false
gridVisible: false
subGridVisible: false
labelsVisible: false
visible: false
}
axisY: ValueAxis {
max: 10
subTickCount: 9
lineVisible: false
gridVisible: false
subGridVisible: false
labelsVisible: false
visible: false
}
ToolTip {
id: tooltip
}
onHoverEnter: {
tooltip.visible = true;
}
onHoverExit: {
tooltip.visible = false;
}
onHover: (seriesName, position, value) => {
tooltip.x = position.x + 1;
tooltip.y = position.y + 1;
tooltip.text = "Altitude: " + (value.y * 1000).toFixed(1) + "m";
}
FrameAnimation {
property var points: []
Component.onCompleted: {
for (let i = 0; i < altitudeLine.count; ++i) {
points[i] = altitudeLine.at(i)
}
}
running: true
onTriggered: {
for (let i = 0; i < points.length; ++i) {
points[i].x -= frameTime
if (points[1].x <= -2) {
let p = points[0]
p.x = points[points.length - 1].x + 1
altitudeLine.append(p)
altitudeLine.remove(0)
points.length = 0
for (let i = 0; i < altitudeLine.count; ++i) {
points[i] = altitudeLine.at(i)
}
}
}
altitudeLine.replace(points)
altitudeLine.update()
}
}
SplineSeries {
id: altitudeLine
hoverable: true
width: 3
XYPoint {x: 0; y: 5}
XYPoint {x: 1; y: 2}
XYPoint {x: 2; y: 5}
XYPoint {x: 3; y: 4}
XYPoint {x: 4; y: 6}
XYPoint {x: 5; y: 7}
XYPoint {x: 6; y: 9}
XYPoint {x: 7; y: 8}
XYPoint {x: 8; y: 9}
XYPoint {x: 9; y: 6}
XYPoint {x: 10; y: 6}
XYPoint {x: 11; y: 6}
XYPoint {x: 12; y: 1}
XYPoint {x: 13; y: 9}
XYPoint {x: 14; y: 1}
}
}© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.