Accessing Qt Charts with QDateTimeAxis in QML from C++
-
wrote on 5 Jul 2017, 10:22 last edited by
I have a problem with Qt charts and with QDateTimeAxis. Inserted data won't display properly, when series is edited from C++ class. In main.qml I have only ChartView which is edited from C++ class DataHandler. DataHandler generates random data every second with current time stamp and edits the series in chart correspondigly. Also chart x-axis is edited dynamically. Changing the QDateTimeAxis to ValueAxis fixes the problem, but then the data time won't be in readable format in chart.
Here is main.cpp
#include <QGuiApplication> #include <QApplication> #include <QQmlApplicationEngine> #include <QQmlEngine> #include <QQmlContext> #include <QQmlComponent> #include "datahandler.h" int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication app(argc, argv); QQmlApplicationEngine engine; QQmlComponent component(&engine, QUrl(QLatin1String("qrc:/main.qml"))); QObject *object = component.create(); QScopedPointer<DataHandler> datahandler(new DataHandler(object)); engine.rootContext()->setContextProperty("datahandler", datahandler.data()); return app.exec(); }
Here is datahandler.h
#ifndef DATAHANDLER_H #define DATAHANDLER_H #include <QObject> #include <QtCharts> QT_CHARTS_USE_NAMESPACE class DataHandler : public QObject { Q_OBJECT public: DataHandler(QObject* object, QObject *parent = 0); ~DataHandler(); private: QTimer* m_timer; QObject* m_object; QObject* m_chart; QVector<QPointF> m_data1, m_data2; public slots: void addValues(); }; #endif // DATAHANDLER_H
...and datahandler.cpp
#include "datahandler.h" #include <QObject> #include <QTimer> #include <QDateTime> #include <QDebug> DataHandler::DataHandler(QObject* object, QObject *parent) { m_timer = new QTimer(); m_object = object; connect(m_timer, &QTimer::timeout, this, &DataHandler::addValues); m_chart = m_object->findChild<QObject*>("chart"); m_timer->start(1000); } DataHandler::~DataHandler(){ } void DataHandler::addValues(){ if(m_chart){ //Generate the data m_data1.append(QPointF(QDateTime::currentMSecsSinceEpoch(), qrand() % 100)); m_data2.append(QPointF(QDateTime::currentMSecsSinceEpoch(), qrand() % 100)); QAbstractSeries *series1; QAbstractSeries *series2; QAbstractAxis *xAxis; //Fetch the series and x-axis from QML QMetaObject::invokeMethod(m_chart, "series", Qt::AutoConnection, Q_RETURN_ARG(QAbstractSeries*, series1), Q_ARG(int, 0)); QMetaObject::invokeMethod(m_chart, "series", Qt::AutoConnection, Q_RETURN_ARG(QAbstractSeries*, series2), Q_ARG(int, 1)); QMetaObject::invokeMethod(m_chart, "axisX", Qt::AutoConnection, Q_RETURN_ARG(QAbstractAxis*, xAxis)); //Cast the series and axis to proper form QXYSeries* xyseries1 = static_cast<QXYSeries *>(series1); QXYSeries* xyseries2 = static_cast<QXYSeries *>(series2); QDateTimeAxis* dateTimeAxis = static_cast<QDateTimeAxis *>(xAxis); //set the new values to series and axises xyseries1->replace(m_data1); xyseries2->replace(m_data2); dateTimeAxis->setMax(QDateTime::fromMSecsSinceEpoch(m_data1.last().x())); dateTimeAxis->setMin(QDateTime::fromMSecsSinceEpoch(m_data1.first().x())); } }
Here is main.qml
import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.3 import QtCharts 2.0 ApplicationWindow { visible: true width: 640 height: 480 title: qsTr("Hello World") ChartView{ id: chart objectName: "chart" antialiasing: true legend.visible: false width: parent.width height: parent.height anchors.fill: parent theme: ChartView.ChartThemeBlueCerulean ValueAxis{ id:axisY min:0 max:100 } DateTimeAxis{ id:dateTime format: "hh:mm:ss" tickCount: 5 } LineSeries{ id:series1 objectName: "series1" axisX: dateTime axisY: axisY useOpenGL: true } LineSeries{ id: series2 objectName: "series2" axisX: dateTime axisY: axisY useOpenGL: true } } }
and ChartTest.pro file
QT += qml quick widgets charts CONFIG += c++11 SOURCES += main.cpp \ datahandler.cpp RESOURCES += qml.qrc # Additional import path used to resolve QML modules in Qt Creator's code model QML_IMPORT_PATH = # Additional import path used to resolve QML modules just for Qt Quick Designer QML_DESIGNER_IMPORT_PATH = # The following define makes your compiler emit warnings if you use # any feature of Qt which as been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target HEADERS += \ datahandler.h
-
wrote on 6 Jul 2017, 11:53 last edited by
I got the program working, by deleting and generating new series every time the chart update is required. First I delete and generate new series in QML and then call the addValues() function in C++ side. This solves the problem, but does not change the fact that there seems to be something wrong with the QDateTimeSeries update.
-
wrote on 6 Jul 2017, 12:38 last edited by
I noticed that the actual cause of the problem is in LineSeries useOpenGL property. When OpenGL is on, the series won't update properly. After turnign OpenGL off, everything works just fine.
-
I noticed that the actual cause of the problem is in LineSeries useOpenGL property. When OpenGL is on, the series won't update properly. After turnign OpenGL off, everything works just fine.
wrote on 7 Jul 2017, 06:49 last edited by@54474N4
There seems to be QT bug report about the issue:
https://bugreports.qt.io/browse/QTBUG-59674?jql=text ~ "OpenGL double float"
2/4