c++qtqtchartsqdebug

How to fix "index < m_series->count()" error in xychart.cpp?


I started to use QtCharts in my application. The chart that I am considering is a Line Chart, using the objects QChart and QLineSeries. As all the points are added dynamically, I use the signal/slot system to update the chart:

QLineSeries* serie = new QLineSeries(this);
connect(serie, SIGNAL(pointAdded(int)), this, SLOT(onPointAdded(int)));

void MyChart::onPointAdded(int index) {
    // Delete the first items if the number of points has reached a threshold
    while (serie->points().length() >= threshold)
        serie->remove(0);
}

The function onPointAdded is called when a point is added in serie (a QLineSeries object). The code snippet that I gave removes the first points in serie such as the number of points in the graph is always fixed (except at the beginning).

When I run this code in Release, there is no problem. However, when I run it on Debug and the number of points reaches the threshold, I obtain the following error message:

Qt Debug Error Message

This dialog box does not stop the program, but each time a point is added (and reach the threshold) a new dialog box appears on top of the previous one.

The following is the minimal code to reproduce the error:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QChart>
#include <QLineSeries>
#include <QMainWindow>
#include <QValueAxis>
#include <QtCharts/QChart>
#include <QtCharts/QLineSeries>

QT_CHARTS_USE_NAMESPACE

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    QChart* chart = nullptr;
    QLineSeries* serie = nullptr;
    int threshold = 5;

private slots:
    void onAddPointButtonClicked();
    void onPointAdded(int index);
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent), ui(new Ui::MainWindow) {
    ui->setupUi(this);

    chart = new QChart;
    serie = new QLineSeries(this);

    connect(ui->bt_addPoint, SIGNAL(clicked()), this, SLOT(onAddPointButtonClicked()));
    connect(serie, SIGNAL(pointAdded(int)), this, SLOT(onPointAdded(int)));

    chart->legend()->hide();
    chart->addSeries(serie);

    ui->graphicsView->setChart(chart);
}

MainWindow::~MainWindow() {
    delete ui;
}

void MainWindow::onAddPointButtonClicked() {
    serie->append(0, 1);
}

void MainWindow::onPointAdded(int index) {
    while (serie->points().length() >= threshold)
        serie->remove(0);
}

I used an UI Form to generate the graphical interface. This interface contains a QChartView and a QPushButton (to add dynamically the points).

My Qt version is 5.11.2, and the bug has been produced using MSVC 2017 64-bits. The plugin QtCharts is needed to use the QChart, QChartView and QLineSeries.

I would like to know if it is possible to either fix this problem or to disable the Qt Debug Dialog Messages.


Solution

  • Cause

    It is not a bug, but an expected result of the order in which the slots MainWindow::onPointAdded (in your code) and XYChart::handlePointAdded are executed. Here is the whole story:

    From the error message it becomes clear, that in the file xychart.cpp on line 142 the check of index against the count of m_series fails. The thing, which invalidates the check, is your serie->remove(0);. The reason is that your slot is executed before the slot, where the check is made, because your connect statement comes first. The question is: first to what? Well, this is the tricky part and I have to admit that it is indeed not immediatelly obvious. However, with some digging in the source code, one could get to the bottom of the problem. The path is the following:

    Focusing only on the steps marked as important, it becomes obvious in which order do both connect statements come. This is also the order in which the respective slots are called.

    Solution

    Having this cause in mind, I would suggest you to first add the series to the chart and then connect the pointAdded signal, i.e.:

    move

    connect(serie, SIGNAL(pointAdded(int)), this, SLOT(onPointAdded(int)));
    

    anywhere after

    chart->addSeries(serie);