Dynamically add point to LineSeries of QML Qt Graphs
-
I'd like to reproduce the same type of application as the Qml Oscilloscope example i.e. display real-time data on 2d line graph. Qml Oscilloscope is implemented using Qt Chart and I want to do the same but with Qt Graphs. This seems to be possible because the documentation says that "It's especially useful for visualizing depth maps and large quantities of rapidly changing data, such as data received from multiple sensors. " but looking at the LineSeries QML Type members and at all inherited members, there is no method to achieve this.
Looking at header source of QXYSeries, which is the base class for QLineSeries you can read the following comment : "// TODO: Consider making these slots, available from QML." in front of all useful methods such as void append(qreal x, qreal y);
I've derived a class from QLineSeries class to make this method invocable. This seems to work (I can add point to a LineSerie) but I haven't find how to refresh the GraphsView. I tried to call update on the graph and other stuff like this but with no results.
I noticed that if you add points to a LineSerie and to stretch the main window, I can see the graph line for a second and the application crash immediately after.
Do you have any ideas how to refresh the graph after adding points to SerialLines?
Main.qml
import QtQuick import QtGraphs import dynamicGraphs Window { width: 640 height: 480 visible: true property int range : 100 Timer { interval: 500; running: true; repeat: true onTriggered: { mySerie.append(Math.round(2*range*Math.random())-range, Math.round(2*range*Math.random())-range) print(mySerie.count(), mySerie.points()) } } GraphsView { id : graphs anchors.fill: parent // LineSeries { LineSeriesWrapper { id : mySerie color: "#00ff00" axisX: ValueAxis { min : -range max : range } axisY: ValueAxis { min : -range max : range } /* XYPoint { x: 0; y: 0 } XYPoint { x: 1; y: 2.1 } XYPoint { x: 2; y: 3.3 } XYPoint { x: 3; y: 2.1 } XYPoint { x: 4; y: 4.9 } XYPoint { x: 5; y: 3.0 } */ } } }
lineserieswrapper.h
#ifndef LINESERIESWRAPPER_H #define LINESERIESWRAPPER_H #include <QLineSeries> class LineSeriesWrapper : public QLineSeries { Q_OBJECT QML_ELEMENT public: explicit LineSeriesWrapper(QObject *parent = nullptr); Q_INVOKABLE void append(qreal, qreal); Q_INVOKABLE int count(); Q_INVOKABLE QList<QPointF> points(); }; #endif // QLINESERIESWRAPPER_H
lineserieswrapper.cpp
#include "lineserieswrapper.h" LineSeriesWrapper::LineSeriesWrapper(QObject *parent) : QLineSeries{parent} {} void LineSeriesWrapper::append(qreal x, qreal y) { QLineSeries::append(x, y); } int LineSeriesWrapper::count() { return QLineSeries::count(); } QList<QPointF> LineSeriesWrapper::points() { return QLineSeries::points(); }
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; QObject::connect( &engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.loadFromModule("dynamicGraphs", "Main"); return app.exec(); }
CMakeLists.txt
cmake_minimum_required(VERSION 3.16) project(dynamicGraphs VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 6.7 REQUIRED COMPONENTS Quick Graphs) qt_standard_project_setup(REQUIRES 6.7) qt_add_executable(appdynamicGraphs main.cpp ) qt_add_qml_module(appdynamicGraphs URI dynamicGraphs VERSION 1.0 QML_FILES Main.qml SOURCES lineserieswrapper.h lineserieswrapper.cpp ) # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. # If you are developing for iOS or macOS you should consider setting an # explicit, fixed bundle identifier manually though. set_target_properties(appdynamicGraphs PROPERTIES # MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appdynamicGraphs MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} MACOSX_BUNDLE TRUE WIN32_EXECUTABLE TRUE ) target_link_libraries(appdynamicGraphs PRIVATE Qt6::Quick Qt6::Graphs ) include(GNUInstallDirs) install(TARGETS appdynamicGraphs BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
-
There was a similar question about this the other day that I looked at. I am not even on Qt6 yet so the following is just from my understanding of the docs and what I know of using QtCharts. The code below is very sketchy and is just to give the idea.
I think you are heading in the right direction that you need to do the update from C++. However, I don't think you should derive from
QLineSeries
. Instead, create aLineSeries
in QML and expose a different C++ class (let's call itDataSource
) to QML that provides anappendToSeries
function. This should take aQLineSeries*
as an argument. In the implementation ofappendToSeries
you will have full access to theQLineSeries
public API.In the following I have assumed that
DataSource
is registered as a "singleton instance":Timer { interval: 500; running: true; repeat: true onTriggered: { DataSource.appendToSeries(mySerie, Math.round(2*range*Math.random())-range, Math.round(2*range*Math.random())-range) print(mySerie.count(), mySerie.points()) } } GraphsView { id : graphs anchors.fill: parent LineSeries { id : mySerie color: "#00ff00" axisX: ValueAxis { min : -range max : range } axisY: ValueAxis { min : -range max : range } } }
-
I've seen several posts on this subject but haven't found a satisfactory solution. The only thing that seems to work is to delete and re-instantiate the entire LineSerie each time a point is added, but I haven't succeeded.
I've implemented your suggestion but the result is the same: the points are added, the GraphicsView remains empty and if I stretch the windows, I can see the graphic for a second and the application crash.
-
OK - my suggestion was essentially the same as the approach taken in the Oscilloscope example. If that isn't working, I am sorry but I don't have anything else to suggest. Perhaps it is simply that there are some limitations with QtGraphs at the moment.
You could maybe try joining the "Qt Interest" mailing list (https://lists.qt-project.org/listinfo/interest) and asking there.
-
-
This post is deleted!