Accessing Qt Charts with QDateTimeAxis in QML from C++



  • 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
    
    


  • 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.



  • 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.




Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.