Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update/redraw QChart after data is added to QLineSeries?

I am generating some data that I want to chart using QChart & friends. This is my first time using QChart, and so basically what I did was copy the QLineSeries Example and modify it to my needs. My current code looks like this:

    quint64 last=0;
    quint64 *lastp=&last;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , series( nullptr )
{
    ui->setupUi(this);
    QChart *chart = new QChart();
    series=new QLineSeries(chart);
    chart->legend()->hide();
    chart->addSeries(series);
    chart->createDefaultAxes();
    chart->setTitle("Simple line chart example");
    QChartView *chartView = new QChartView(chart);
    chartView->setRenderHint(QPainter::Antialiasing);
    setCentralWidget(chartView);
    GeneticTask *gTask = new GeneticTask();
    connect(gTask, &GeneticTask::point, this, [=](QPointF pt) {
        // New point added to series
        *series<<pt;
        // Limit updates to once per second
        quint64 now=QDateTime::currentMSecsSinceEpoch();
        if(now-(*lastp)>1000) {
            qDebug()<<"UPDATE";
            // [A] WHAT TO PUT HERE TO HAVE CHART REDRAW WITH NEW DATA?
            *lastp=now;
        }
    }
    );
    QThreadPool::globalInstance()->start(gTask);
}

When I run this code I would expect my new data to show up in the graph, but it does not, so my question is: How can I have the chart update to show the new data? In other words, what should I put in the code where the comment reads [A]?

like image 572
Lennart Rolland Avatar asked Mar 24 '17 23:03

Lennart Rolland


2 Answers

Appending a value to QLineSeries using the operator << or the append method should repaint the graph. If it does not happen form some reason, you could trying calling the repaint method on the QChartView.

Here is some code that will center the data once it is added with a cap of at most once per second:

// Global or class scope or
qreal max=-10000000000;
qreal min=-max;
qreal *maxp=&max;
qreal *minp=&min;

// Same scope as before
connect(gTask, &GeneticTask::point, this, [=](QPointF pt) {
        if(pt.y()>*maxp) {
            *maxp=pt.y();
        }
        if(pt.y()<*minp) {
            *minp=pt.y();
        }
        *series<<pt;
        quint64 now=QDateTime::currentMSecsSinceEpoch();
        if(now-(*lastp)>1000) {
            qDebug()<<"UPDATE";
            chart->axisX()->setRange(0,series->count());
            chart->axisY()->setRange(*minp,*maxp);

            *lastp=now;
        }
    }
);
like image 197
Ervin Szilagyi Avatar answered Sep 17 '22 22:09

Ervin Szilagyi


Little correction to the answer above. Qt Documentation says:

void QWidget::repaint() Repaints the widget directly by calling paintEvent() immediately, unless updates are disabled or the widget is hidden. We suggest only using repaint() if you need an immediate repaint, for example during animation. In almost all circumstances update() is better, as it permits Qt to optimize for speed and minimize flicker.
Warning: If you call repaint() in a function which may itself be called from paintEvent(), you may get infinite recursion. The update() function never causes recursion.

As result, QChartView::update() works for me.

like image 20
Alex Kart Avatar answered Sep 16 '22 22:09

Alex Kart