如何修复 xychart.cpp 中的 "index < m_series->count()" 错误?

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

我开始使用QtCharts in my application. The chart that I am considering is a Line Chart, using the objects QChart and QLineSeries。由于所有点都是动态添加的,我使用signal/slot系统更新图表:

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);
}

serie(一个QLineSeries对象)中添加一个点时调用函数onPointAdded。我给出的代码片段删除了 serie 中的第一个点,例如图中的点数始终是固定的(开头除外)。

当我运行这段代码在Release时,没有问题。但是,当我 运行 它在 Debug 并且点数达到阈值时,我收到以下错误消息:

此对话框不会停止程序,但每次添加一个点(并达到阈值)时,都会在前一个对话框之上出现一个新对话框。

以下是重现错误的最少代码:

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);
}

我使用了一个UI表单来生成图形界面。该接口包含一个QChartView and a QPushButton(动态添加点数)。

我的Qt版本是5.11.2,bug是用MSVC 2017 64-bits产生的。插件 QtCharts 需要使用 QChart, QChartViewQLineSeries.

我想知道是否可以解决此问题或禁用 Qt 调试对话框消息。

原因

这不是错误,而是插槽 MainWindow::onPointAdded(在您的代码中)和 XYChart::handlePointAdded 执行顺序的预期结果。这是整个故事:

从错误消息中可以清楚地看出,在文件 xychart.cpp 的第 142 行,indexm_series 的计数检查失败。使支票无效的是你的 serie->remove(0);。原因是您的插槽在 之前 进行检查的插槽执行,因为您的 connect 语句首先出现。问题是:首先要什么?好吧,这是棘手的部分,我不得不承认它确实不是很明显。然而,通过深入挖掘源代码,可以找到问题的根源。路径如下:

  • chart = new QChart; 在你的代码中实例化了一个 QChart,它又 instantiates 一个 PIMPL QChartPrivate

  • QChartPrivate connects in it's constructor ChartDataSet::seriesAddedChartPresenter::handleSeriesAdded:

      QObject::connect(m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)), m_presenter, SLOT(handleSeriesAdded(QAbstractSeries*)));
    
  • 重要 现在您将 QLineSeries::pointAdded 连接到 MainWindow::onPointAdded

  • chart->addSeries(serie); 在您的代码中导致 ChartPresenter::handleSeriesAdded 槽被执行,其中 QLineSeriesPrivate::initializeGraphics 被调用:

      series->d_ptr->initializeGraphics(rootItem());
    
  • QLineSeriesPrivate::initializeGraphics中实例化了一个LineChartItem

      LineChartItem *line = new LineChartItem(q,parent);
    
  • LineChartItem calls其基class的构造函数XYChart其自身构造函数

    的初始化列表
  • 重要 只是现在是 connect 语句 executed,这会给你带来麻烦 XYChart::handlePointAdded 插槽当一个点被添加到系列时被调用:

      QObject::connect(series, SIGNAL(pointAdded(int)), this, SLOT(handlePointAdded(int)));
    

只关注标记为重要的步骤,两个 connect 语句的顺序就很明显了。这也是调用各个插槽的顺序。

解决方案

考虑到这个原因,我建议您先将系列添加到图表中,然后然后连接pointAdded信号,即:

移动

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

任何地方

之后
chart->addSeries(serie);