Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Real-time update of QChart



  • I am receiving a string over a bluetooth connection which contains values from 3 different sensors. I am using Qchart (bars) to display incoming data.

    ***How can I update the QChart without flickering the display (smooth data update)***? Because so far I have managed to display incoming data but the display is flickering every time it updates the value.



  • Hello!
    What do you mean flickering, dear?



  • @closx I want only the bar graphs to get updated corresponding to the incoming values. but the whole Qchart refreshes itself (this is quite annoying to see).



  • @ahsan737 Oh! Kinda got it. So, how do you receive the update in code? Can you share with us?



  • @closx sure, this is the code: ```
    #include "mainwindow1.h"
    #include "ui_mainwindow1.h"
    #include<QtBluetooth>
    #include<QBluetoothSocket>
    #include <QTimer>

    #include <QApplication>
    #include <QtWidgets/QMainWindow>
    #include <QtCharts/QChartView>
    #include <QtCharts/QBarSeries>
    #include <QtCharts/QBarSet>
    #include <QtCharts/QLegend>
    #include <QtCharts/QBarCategoryAxis>
    #include <QtCharts/QHorizontalStackedBarSeries>
    #include <QtCharts/QLineSeries>
    #include <QtCharts/QCategoryAxis>
    #include <QtCharts/QPieSeries>
    #include <QtCharts/QPieSlice>

    QT_CHARTS_USE_NAMESPACE

    MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)

    {
    //Chart Display
    // chartDisp();

    // Turn Bluetooth on
    localDevice.powerOn();
    
    connect(agent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
            this, SLOT(deviceDiscovered(QBluetoothDeviceInfo)));
    //connect(this, &MainWindow::messageReceived,this, &MainWindow::showMessage);
    
    agent->start();
    socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
    readSocket();
    /********Run Timer to Recieve Bluetooth Data**********/
    
    timer = new QTimer(this);
    timer1 = new QTimer(this);
    //connect(timer, &QTimer::timeout, contextObj, []{/* your code here */});
    connect(timer, SIGNAL(timeout()),this, SLOT(readSocket()));
    
    connect(timer, SIGNAL(timeout()),this, SLOT(socketStatuscheck()));
    connect(timer1, SIGNAL(timeout()),this, SLOT(chartDisp()));
    
    
    timer->start(50);
    timer->start(1000);
    /*-----------------------------------------------------*/
    

    }

    MainWindow::~MainWindow()
    {
    }

    //****************************************************************************
    void MainWindow::deviceDiscovered(const QBluetoothDeviceInfo &device)
    {
    //ui->listWidget->addItem(device.address().toString());
    //ui->listWidget->addItem(device.name());

    static const QString serviceUuid(QStringLiteral("00001101-0000-1000-8000-00805F9B34FB"));
    socket->connectToService(QBluetoothAddress("20:19:03:29:27:62"), QBluetoothUuid(serviceUuid), QIODevice::ReadWrite);
    

    }
    //****************************************************************************
    void MainWindow::readSocket()
    {
    //QBluetoothSocket *socket = qobject_cast<QBluetoothSocket *>(sender());
    // if (!socket)
    // return;

    while (socket->canReadLine()) {
        QByteArray line = socket->readLine().trimmed();
        emit messageReceived(socket->peerName(),
                               QString ::fromUtf8(line.constData(), line.length()));
    
    
    
        QStringList lista, listc, listd;
        QString listb= QString::fromUtf8(line.constData(), line.length());
    
        lista= listb.split(",");
        listc=lista.at(2).split("@");
        listd=listc.at(1).split("~");
    

    //****************************************************************
    a=lista.at(1).toInt();
    b=listc.at(0).toInt();
    c=listd.at(0).toInt();
    //*****************************************************************
    QString result;
    result.append(lista.at(1));
    result.append("\n");
    result.append(listc.at(0));
    result.append("\n");
    result.append(listd.at(0));
    }
    }
    //****************************************************************************
    void MainWindow::chartDisp()
    {

    // Assign names to the set of bars used
    QBarSet *set0 = new QBarSet("Sensor 1");
    QBarSet *set1 = new QBarSet("Sensor 2");
    QBarSet *set2 = new QBarSet("Sensor 3");
    
    
    // Assign values for each bar
    *set0 << a;
    *set1 << b;
    *set2 << c;
    
    // Add all sets of data to the chart as a whole
    // 1. Bar Chart
    QBarSeries *series = new QBarSeries();
    
    // 2. Stacked bar chart
    // QHorizontalStackedBarSeries *series = new QHorizontalStackedBarSeries();
    
    series->append(set0);
    series->append(set1);
    series->append(set2);
    
    // Used to define the bar chart to display, title
    // legend,
    QChart *chart = new QChart();
    
    // Add the chart
    chart->addSeries(series);
    
    // Set title
    chart->setTitle("Sensor Values");
    
    // Define starting animation
    // NoAnimation, GridAxisAnimations, SeriesAnimations
    chart->setAnimationOptions(QChart::NoAnimation);
    
    // Holds the category titles
    QStringList categories;
    categories << "2013";
    
    // Adds categories to the axes
    QBarCategoryAxis *axis = new QBarCategoryAxis();
    axis->append(categories);
    chart->createDefaultAxes();
    
    // 1. Bar chart
    chart->setAxisX(axis, series);
    
    // 2. Stacked Bar chart
    // chart->setAxisY(axis, series);
    
    // Define where the legend is displayed
    chart->legend()->setVisible(true);
    chart->legend()->setAlignment(Qt::AlignBottom);
    
    // Used to display the chart
    QChartView *chartView = new QChartView(chart);
    chartView->setRenderHint(QPainter::Antialiasing);
    
    // Used to change the palette
    QPalette pal = qApp->palette();
    
    // Change the color around the chart widget and text
    pal.setColor(QPalette::Window, QRgb(0xffffff));
    pal.setColor(QPalette::WindowText, QRgb(0x404044));
    
    // Apply palette changes to the application
    qApp->setPalette(pal);
    setCentralWidget(chartView);
    resize(720,1060);
    

    }

    //****************************************************************************
    void MainWindow::socketStatuscheck()
    {
    int socketState = socket->state();

    if (socketState==QAbstractSocket::ConnectedState)
    {
    

    // ui->label_status->setText("Connected");
    readSocket();
    chartDisp();
    }
    else if(socketState==QAbstractSocket::UnconnectedState)
    {
    // Turn Bluetooth on
    localDevice.powerOn();
    // ui->label_status->setText("DisConnected");
    agent->stop();
    agent->start();
    }

    }



  • @ahsan737 I see in your code, every time that timer changes, it triggers the function chartDisp(). And inside the chartDisp(), you add almost all of your components to the UI. So, this code makes your whole UI refresh (i can say) continuously. To avoid that, you must put the UI component creators (almostly all of your codes inside this function) to the outside (in your main constructor of your class). Only the component that you want to refresh continuously must be changing by the change of time.
    It would be better if you create a widget just for the component that you want to refresh. You create the widget (lets say with the name myWidget) and include the component inside this widget. And inside the chartDisp() function, to update the widget, you can write;

    myWidget.update();
    

    I guess this should work. If wont, post again and we can look for it deeper.



  • @closx thank you for such detailed reply, I will try to do this way although I am still bit confused about how to execute this.



  • @ahsan737
    Hello,

    #include "mainwindow1.h"
    #include "ui_mainwindow1.h"
    #include<QtBluetooth>
    #include<QBluetoothSocket>
    #include <QTimer>
    
    #include <QApplication>
    #include <QtWidgets/QMainWindow>
    #include <QtCharts/QChartView>
    #include <QtCharts/QBarSeries>
    #include <QtCharts/QBarSet>
    #include <QtCharts/QLegend>
    #include <QtCharts/QBarCategoryAxis>
    #include <QtCharts/QHorizontalStackedBarSeries>
    #include <QtCharts/QLineSeries>
    #include <QtCharts/QCategoryAxis>
    #include <QtCharts/QPieSeries>
    #include <QtCharts/QPieSlice>
    
    QT_CHARTS_USE_NAMESPACE
    
    MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
    
    {
    localDevice.powerOn();
    
    connect(agent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
            this, SLOT(deviceDiscovered(QBluetoothDeviceInfo)));
    
    agent->start();
    socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
    readSocket();
    
    timer = new QTimer(this);
    timer1 = new QTimer(this);
    connect(timer, SIGNAL(timeout()),this, SLOT(readSocket()));
    
    connect(timer, SIGNAL(timeout()),this, SLOT(socketStatuscheck()));
    connect(timer1, SIGNAL(timeout()),this, SLOT(chartDisp()));
    timer->start(50);
    timer->start(1000);
    QBarSet *set0 = new QBarSet("Sensor 1");
    QBarSet *set1 = new QBarSet("Sensor 2");
    QBarSet *set2 = new QBarSet("Sensor 3");
    *set0 << a;
    *set1 << b;
    *set2 << c;
    QBarSeries *series = new QBarSeries();
    series->append(set0);
    series->append(set1);
    series->append(set2);
    QChart *chart = new QChart();
    chart->addSeries(series);
    chart->setTitle("Sensor Values");
    chart->setAnimationOptions(QChart::NoAnimation);
    QStringList categories;
    categories << "2013";
    QBarCategoryAxis *axis = new QBarCategoryAxis();
    axis->append(categories);
    chart->createDefaultAxes();
    chart->setAxisX(axis, series);
    chart->legend()->setVisible(true);
    chart->legend()->setAlignment(Qt::AlignBottom);
    QChartView *chartView = new QChartView(chart);
    chartView->setRenderHint(QPainter::Antialiasing);
    QPalette pal = qApp->palette();
    
    pal.setColor(QPalette::Window, QRgb(0xffffff));
    pal.setColor(QPalette::WindowText, QRgb(0x404044));
    
    qApp->setPalette(pal);
    setCentralWidget(chartView);
    resize(720,1060);
    
    
    }
    
    MainWindow::~MainWindow()
    {
    }
    
    void MainWindow::deviceDiscovered(const QBluetoothDeviceInfo &device)
    {
    
    static const QString serviceUuid(QStringLiteral("00001101-0000-1000-8000-00805F9B34FB"));
    socket->connectToService(QBluetoothAddress("20:19:03:29:27:62"), QBluetoothUuid(serviceUuid), QIODevice::ReadWrite);
    
    }
    void MainWindow::readSocket()
    {
    
    while (socket->canReadLine()) {
        QByteArray line = socket->readLine().trimmed();
        emit messageReceived(socket->peerName(),
                               QString ::fromUtf8(line.constData(), line.length()));
    
        QStringList lista, listc, listd;
        QString listb= QString::fromUtf8(line.constData(), line.length());
    
        lista= listb.split(",");
        listc=lista.at(2).split("@");
        listd=listc.at(1).split("~");
    
    a=lista.at(1).toInt();
    b=listc.at(0).toInt();
    c=listd.at(0).toInt();
    QString result;
    result.append(lista.at(1));
    result.append("\n");
    result.append(listc.at(0));
    result.append("\n");
    result.append(listd.at(0));
    }
    }
    void MainWindow::chartDisp()
    {
    
    
        charView.update(); //or charView.repaint();
    
    
    }
    void MainWindow::socketStatuscheck()
    {
    int socketState = socket->state();
    
    if (socketState==QAbstractSocket::ConnectedState)
    {
    readSocket();
    chartDisp();
    }
    else if(socketState==QAbstractSocket::UnconnectedState)
    {
    localDevice.powerOn();
    agent->stop();
    agent->start();
    }
    
    }
    
    

    Maybe something like that may work. Since I dont have qt charts module, I cannot test. I don't have much experience with charts too. You have to use the charts?



  • @closx thank you. I do not necessarily have to use Qcharts. If there is any other option to display data then I will simply opt that. I want to display incoming sensor values with a bar graph and plot them real-time. The required Bar graph (bars color is green, and it turns red when incoming sensor value is above a threshold value) and Line graphs are shown in images attached.

    2_1562807015098_graph_3.JPG 1_1562807015097_graph_2.JPG 0_1562807015095_graph_1.JPG



  • I have successfully implemented it using QCustomPlot.


Log in to reply