简单的散点图

在 QML 应用程序中使用Scatter3D

Simple Scatter Graph展示了如何使用Scatter3D 和 QML 制作简单的散点图可视化。

有关如何与图形交互的说明,请参阅本页

有关如何创建新的Qt Quick 应用程序的说明,请参阅Qt Creator 帮助。

运行示例

运行示例 Qt Creator,打开Welcome 模式,然后从Examples 中选择示例。更多信息,请参阅Qt Creator: 教程:构建并运行

应用程序基础

在深入研究 QML 代码之前,先看看应用程序main.cpp

此应用程序在用户界面中实现了一个 "退出 "按钮,因此您需要将QQmlEngine::quit() 信号连接到应用程序的QWindow::close() 槽:

QObject::connect(viewer.engine(), &QQmlEngine::quit, &viewer, &QWindow::close);

为了使部署工作更简单,请将应用程序的所有.qml 文件都集中到一个资源文件 (qmlscatter.qrc) 中:

<RCC>
    <qresource prefix="/">
        <file>qml/qmlscatter/Data.qml</file>
        <file>qml/qmlscatter/main.qml</file>
    </qresource>
</RCC>

这还需要将main.qml 设置为从资源文件 (qrc:) 中读取:

viewer.setSource(QUrl("qrc:/qml/qmlscatter/main.qml"));

当使用 cmake 而不是 qmake 时,.qml 文件会被添加到CMakeLists.txt 中的 QML 模块中:

qt6_add_qml_module(qmlscatter
    URI Scatter
    VERSION 1.0
    NO_RESOURCE_TARGET_PATH
    QML_FILES
        qml/qmlscatter/Data.qml
        qml/qmlscatter/main.qml
)

最后,让应用程序在最大化窗口中运行:

viewer.showMaximized();

设置图形

首先,导入所有需要的 QML 模块:

import QtQuick
import QtQuick.Controls
import QtDataVisualization

然后,创建主Item 并将其称为mainView

Item {
    id: mainView

然后,在主Item 内添加另一个Item ,并将其称为dataView 。这将是保存Scatter3D 图表的项目。将其锚定到父级底部:

Item {
    id: dataView
    anchors.bottom: parent.bottom

接下来,添加Scatter3D 图表本身。将其添加到dataView 内,并命名为scatterGraph 。使其填充dataView

Scatter3D {
    id: scatterGraph
    anchors.fill: parent

现在,图形已可使用,但没有数据。它还具有默认坐标轴和可视化属性。

接下来,先修改一些可视化属性,在scatterGraph 中添加以下内容:

theme: themeQt
shadowQuality: AbstractGraph3D.ShadowQualityHigh
scene.activeCamera.cameraPreset: Camera3D.CameraPresetFront

添加自定义主题,改变阴影质量,调整摄像头位置。其他可视化属性没有问题,因此无需修改。

自定义主题基于预定义主题Theme3D.ThemeQt ,但其中的字体有所改变:

Theme3D {
    id: themeQt
    type: Theme3D.ThemeQt
    font.pointSize: 40
}

然后,开始向图表输入数据。

向图表添加数据

mainView 中创建Data 项,并将其命名为seriesData

Data {
    id: seriesData
}

seriesData 项包含本示例中使用的所有三个系列的数据模型。

这是保存Data.qml 中数据的组件。它有一个作为主组件的Item

在主组件中,将数据本身添加到ListModel 中,并将其命名为dataModel

ListModel {
    id: dataModel
    ListElement{ xPos: -10.0; yPos: 5.0; zPos: -5.0 }
    ...

在其他两个系列中再添加两个这样的组件,分别命名为dataModelTwodataModelThree

然后,从main.qml 公开数据模型。方法是在主数据组件中将它们定义为别名:

property alias model: dataModel
property alias modelTwo: dataModelTwo
property alias modelThree: dataModelThree

现在,您可以在main.qml 中通过scatterGraph 使用Data.qml 中的数据。首先,添加一个Scatter3DSeries 并将其称为scatterSeries

Scatter3DSeries {
    id: scatterSeries

然后,为系列设置选择标签格式:

itemLabelFormat: "Series 1: X:@xLabel Y:@yLabel Z:@zLabel"

最后,在ItemModelScatterDataProxy 中添加系列一的数据。将数据本身设置为代理的itemModel

ItemModelScatterDataProxy {
    itemModel: seriesData.model
    xPosRole: "xPos"
    yPosRole: "yPos"
    zPosRole: "zPos"
}

用同样的方法添加另外两个系列,但要稍微修改一些特定系列的细节:

Scatter3DSeries {
    id: scatterSeriesTwo
    itemLabelFormat: "Series 2: X:@xLabel Y:@yLabel Z:@zLabel"
    itemSize: 0.05
    mesh: Abstract3DSeries.MeshCube
    ...

然后,修改scatterGraph 中默认坐标轴的属性:

axisX.segmentCount: 3
axisX.subSegmentCount: 2
axisX.labelFormat: "%.2f"
axisZ.segmentCount: 2
axisZ.subSegmentCount: 2
axisZ.labelFormat: "%.2f"
axisY.segmentCount: 2
axisY.subSegmentCount: 2
axisY.labelFormat: "%.2f"

然后,在mainView 中添加几个按钮来控制图表,其中一个按钮如图所示:

Button {
    id: shadowToggle
    width: mainView.buttonWidth // Calculated elsewhere based on screen orientation
    anchors.left: parent.left
    anchors.top: parent.top
    anchors.margins: 5
    text: scatterGraph.shadowsSupported ? "Hide Shadows" : "Shadows not supported"
    enabled: scatterGraph.shadowsSupported
    onClicked: {
        if (scatterGraph.shadowQuality === AbstractGraph3D.ShadowQualityNone) {
            scatterGraph.shadowQuality = AbstractGraph3D.ShadowQualityHigh;
            text = "Hide Shadows";
        } else {
            scatterGraph.shadowQuality = AbstractGraph3D.ShadowQualityNone;
            text = "Show Shadows";
        }
    }
}

然后,修改dataView ,为顶部的按钮腾出一些空间:

Item {
    id: dataView
    anchors.bottom: parent.bottom
    width: parent.width
    // Adjust the space based on screen orientation:
    // If we're in portrait mode, we have 3 rows of buttons, otherwise they are all in one row.
    height: parent.height - (mainView.portraitMode ? shadowToggle.implicitHeight * 3 + 25
                                                   : shadowToggle.implicitHeight + 10)
    ...

这样就大功告成了!

示例内容

示例项目 @ code.qt.io

© 2025 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.