summaryrefslogtreecommitdiffstats
path: root/examples/datavisualization/qml3doscilloscope/doc/src/qml3doscilloscope.qdoc
blob: 7acfc40b9fa8b821d5b61af18e569060a9bf4502 (plain)
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only

/*!
    \example qml3doscilloscope
    \title Qt Quick 2 Oscilloscope Example
    \ingroup qtdatavisualization_examples
    \brief Example of a hybrid C++ and QML application.

    The Qt Quick 2 oscilloscope example shows how to combine C++ and QML in an application,
    as well as showing data that changes realtime.

    \image qml3doscilloscope-example.png

    The interesting thing about this example is combining C++ and QML, so we'll concentrate on
    that and skip explaining the basic functionality - for
    more detailed QML example documentation, see \l{Qt Quick 2 Scatter Example}.

    \include examples-run.qdocinc

    \section1 Data Source in C++

    The item model based proxies are good for simple and/or static graphs, but to achieve
    best performance when displaying data changing in realtime, the basic proxies should be used.
    Those are not supported in QML, as the data items they store are not \l{QObject}s and
    cannot therefore be directly manipulated from QML code.
    To overcome this limitation, we implement a simple \c DataSource class in C++ to populate the
    data proxy of the series.

    The \c DataSource class provides two methods that can be called from QML:

    \snippet qml3doscilloscope/datasource.h 0

    The first method, \c generateData(), creates a cache of simulated oscilloscope data for us
    to display. The data is cached in a format accepted by QSurfaceDataProxy:

    \snippet qml3doscilloscope/datasource.cpp 0

    The second method, \c update(), copies one set of the cached data into another array, which we
    set to the data proxy of the series by calling QSurfaceDataProxy::resetArray().
    We reuse the same array if the array dimensions have not changed to minimize overhead:

    \snippet qml3doscilloscope/datasource.cpp 1

    \note Even though we are operating on the array pointer we have previously set to the proxy
    we still need to call QSurfaceDataProxy::resetArray() after changing the data in it to prompt
    the graph to render the data.

    To be able to access the \c DataSource methods from QML, we need to expose it. We do this by
    making the DataSource a QML_ELEMENT:

    \snippet qml3doscilloscope/datasource.h 1

    In addition to that, it needs to be declared as a QML module in the CMakeLists.txt:

    \badcode
    qt6_add_qml_module(qml3doscilloscope
        URI DataSource
        VERSION 1.0
        NO_RESOURCE_TARGET_PATH
        SOURCES
            datasource.cpp datasource.h
        QML_FILES
            qml/qml3doscilloscope/main.qml
    )
    \endcode

    To make it possible to use QSurface3DSeries pointers as parameters on the
    \c DataSource class methods on all environments and builds, we need to make sure the meta
    type is registered:

    \snippet qml3doscilloscope/datasource.cpp 3
    \dots 0
    \snippet qml3doscilloscope/datasource.cpp 4

    \section1 QML

    To be able to use the \c{DataSource}, we need to import the QML module, and create an
    instance of it to be used:

    \snippet qml3doscilloscope/qml/qml3doscilloscope/main.qml 0
    \dots 0
    \snippet qml3doscilloscope/qml/qml3doscilloscope/main.qml 5

    We define a Surface3D graph normally and give it a Surface3DSeries:

    \snippet qml3doscilloscope/qml/qml3doscilloscope/main.qml 0

    One interesting detail is that we don't specify a proxy for the Surface3DSeries we attach
    to the graph. This makes the series to utilize the default QSurfaceDataProxy.

    We also hide the item label with \l{Abstract3DSeries::itemLabelVisible}{itemLabelVisible}, since
    we want to display the selected item information in a \c Text element instead of a floating
    label above the selection pointer.
    This is done because the selection pointer moves around a lot as the data changes, which makes
    the regular selection label difficult to read.

    We initialize the \c DataSource cache when the graph is complete by calling a helper function
    \c generateData(), which calls the method with the same name on the \c DataSource:

    \snippet qml3doscilloscope/qml/qml3doscilloscope/main.qml 2
    \dots 4
    \snippet qml3doscilloscope/qml/qml3doscilloscope/main.qml 4

    To trigger the updates in data, we define a \c Timer item which calls the \c update() method on the \c
    DataSource at requested intervals. The label update is also triggered on each cycle:

    \snippet qml3doscilloscope/qml/qml3doscilloscope/main.qml 3

    \section1 Enabling Direct Rendering

    Since this application potentially deals with a lot of rapidly changing data, we use direct
    rendering mode for performance. To enable antialiasing in this mode the surface format of the application
    window needs to be changed, as the default format used by QQuickView doesn't support antialiasing.
    We use the utility function provided by Qt Data Visualization to change the surface format
    in \c main.cpp:

    \snippet qml3doscilloscope/main.cpp 1
    \dots 0
    \snippet qml3doscilloscope/main.cpp 2

*/