Как исправить ошибку "index <m_series->count()" в xychart.cpp?

Я начал использовать QtCharts в моем приложении. Диаграмма, которую я рассматриваю, представляет собой линейную диаграмму с использованием объектов. QChart а также QLineSeries, Поскольку все точки добавляются динамически, я использую систему сигнал / слот для обновления графика:

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

Функция onPointAdded вызывается при добавлении точки в serieQLineSeries объект). Фрагмент кода, который я дал, удаляет первые точки в serie например, количество точек на графике всегда фиксировано (кроме как в начале).

Когда я запускаю этот код в Release, нет проблем. Тем не менее, когда я запускаю его на Debug и количество баллов достигает порога, я получаю следующее сообщение об ошибке:

Сообщение об ошибке Qt 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 Form для создания графического интерфейса. Этот интерфейс содержит QChartView и QPushButton (динамически добавлять точки).

Моя версия Qt - 5.11.2, и ошибка была создана с использованием MSVC 2017 64-bit. Плагин QtCharts необходим для использования QChart, QChartView а также QLineSeries,

Я хотел бы знать, возможно ли исправить эту проблему или отключить сообщения диалога отладки Qt.

1 ответ

Решение

причина

Это не ошибка, но ожидаемый результат порядка, в котором слоты MainWindow::onPointAdded (в вашем коде) и XYChart::handlePointAdded выполнены. Вот вся история:

Из сообщения об ошибке становится ясно, что в файле xychart.cpp по строке 142 проверка index против счета m_series выходит из строя. То, что делает чек недействительным, это ваша serie->remove(0);, Причина в том, что ваш слот выполняется перед слотом, где производится проверка, потому что ваш connect утверждение приходит первым. Вопрос: сначала к чему? Ну, это сложная часть, и я должен признать, что это действительно не сразу очевидно. Однако, покопавшись в исходном коде, можно добраться до сути проблемы. Путь следующий:

  • chart = new QChart; в вашем коде создает экземпляр QChart который в свою очередь создает экземпляр PIMPL QChartPrivate

  • QChartPrivate подключается в своем конструкторе ChartDataSet::seriesAdded в ChartPresenter::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 вызывает конструктор своего базового класса XYChart в списке инициализатора своего собственного конструктора

  • ВАЖНО Только сейчас connect Выписка выполнена, что вызывает у вас неприятности 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);
Другие вопросы по тегам