Как исправить ошибку «index <m_series-> count ()» в xychart.cpp? - PullRequest
0 голосов
/ 27 октября 2018

Я начал использовать 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 вызывается при добавлении точки в serie (объект QLineSeries). Приведенный мною фрагмент кода удаляет первые точки в serie, например, количество точек на графике всегда фиксировано (кроме как в начале).

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

Qt Debug Error Message

Это диалоговое окно не останавливает программу, но каждый раз, когда точка добавляется (и достигает порога), появляется новое диалоговое окно поверх предыдущего.

Ниже приведен минимальный код для воспроизведения ошибки:

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-бит . Плагин QtCharts нужен для использования QChart, QChartView и QLineSeries.

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

1 Ответ

0 голосов
/ 28 октября 2018

Причина

Это не ошибка, а ожидаемый результат порядка, в котором исполняются слоты 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());
    
  • In QLineSeriesPrivate::initializeGraphics a LineChartItem:

    LineChartItem *line = new LineChartItem(q,parent);
    
  • LineChartItem вызывает конструктор своего базового класса XYChart в списке инициализаторов своего собственного конструктора

  • ВАЖНО Только сейчас connect оператор выполнен , что вызывает проблемный для вас слот XYChart::handlePointAdded, вызываемый при добавлении точки в ряд:

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

Фокусировка только нашаги, помеченные как важные, становится очевидным, в каком порядке connect statПриходят элементы.Это также порядок, в котором называются соответствующие слоты.

Решение

Имея в виду эту причину, я бы посоветовал вам сначала добавить серию на график и , затем подключить сигнал pointAdded, то есть:

переместить

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

куда угодно после

chart->addSeries(serie);
...