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:
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.
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:
chart = new QChart;
in your code instantiates a QChart
, which in turn instantiates a PIMPL QChartPrivate
QChartPrivate
connects in it's constructor ChartDataSet::seriesAdded
to ChartPresenter::handleSeriesAdded
:
QObject::connect(m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)), m_presenter, SLOT(handleSeriesAdded(QAbstractSeries*)));
IMPORTANT Now you connect QLineSeries::pointAdded
to MainWindow::onPointAdded
chart->addSeries(serie);
in your code causes the ChartPresenter::handleSeriesAdded
slot to be executed, where QLineSeriesPrivate::initializeGraphics
is called:
series->d_ptr->initializeGraphics(rootItem());
In QLineSeriesPrivate::initializeGraphics
a LineChartItem
is instantiated:
LineChartItem *line = new LineChartItem(q,parent);
LineChartItem
calls the constructor of its base class XYChart
in the initializer list of its own constructor
IMPORTANT Only now is the connect
statement executed, which causes the troublesome for you XYChart::handlePointAdded
slot to be called when a point is added to the series:
QObject::connect(series, SIGNAL(pointAdded(int)), this, SLOT(handlePointAdded(int)));
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.
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);