/**************************************************************************** ** ** Copyright (C) 2014 Digia Plc ** All rights reserved. ** For any questions to Digia, please use contact form at http://qt.digia.com ** ** This file is part of the QtDataVisualization module. ** ** Licensees holding valid Qt Enterprise licenses may use this file in ** accordance with the Qt Enterprise License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. ** ** If you have questions regarding the use of this file, please use ** contact form at http://qt.digia.com ** ****************************************************************************/ /*! \example qmloscilloscope \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 qmloscilloscope-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}. \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 three methods that can be called from QML: \snippet qmloscilloscope/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 qmloscilloscope/datasource.cpp 0 The secod 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 qmloscilloscope/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 defining a context property in application main: \snippet qmloscilloscope/main.cpp 0 To make it possible to use Qt Data Visualization class pointers as parameters on the \c DataSource class methods on all environments and builds, we need to make sure the meta types are registered: \snippet qmloscilloscope/datasource.cpp 3 \dots 0 \snippet qmloscilloscope/datasource.cpp 4 \section1 QML In the QML codes, we define a Surface3D graph normally and give it a Surface3DSeries: \snippet qmloscilloscope/qml/qmloscilloscope/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}{itemLabelFormat}, 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 qmloscilloscope/qml/qmloscilloscope/main.qml 2 \dots 4 \snippet qmloscilloscope/qml/qmloscilloscope/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 qmloscilloscope/qml/qmloscilloscope/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 qmloscilloscope/main.cpp 1 \dots 0 \snippet qmloscilloscope/main.cpp 2 On the QML side, direct rendering mode is enabled via \l{AbstractGraph3D::renderingMode}{renderingMode} property: \snippet qmloscilloscope/qml/qmloscilloscope/main.qml 5 */