Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: PazDim от Декабрь 12, 2018, 13:35



Название: QChart - проблемы с обновлением списка
Отправлено: PazDim от Декабрь 12, 2018, 13:35
Добрый день.
Если задача построения скользящего графика. Ось X - QDateTimeAxis, ось Y - QValueAxis. Сначала нужно загрузить 18000 точек, потом каждую секунду обновлять график - добавлять в начало точку, убирать из конца точку. Как создаю график:
Код:
/* Создаем график */
QChart *chart = new QChart;

/* Создаем область для вывода */
QChartView *view = new QChartView(chart);
m_layout->addWidget(view, i, 0);

/* Создаем линию */
QLineSeries *line = new QLineSeries();

/* Создаем ось X */
QDateTimeAxis *axisX = new QDateTimeAxis;
axisX->setTickCount(10);
axisX->setFormat("yyyy-MM-dd<br>hh:mm:ss");
axisX->setReverse(true);
/* Устанавливаем диапазон оси */
axisX->setMax(startTime);
axisX->setMin(startTime.addSecs(-interval));
chart->setAxisX(axisX);

/* Создаем ось Y */
QValueAxis *axisY = new QValueAxis();
axisY->setLabelFormat("%i");
axisY->setRange(0.0, 0.0);
chart->setAxisY(axisY);


...


/* Привязываем линии к графикам и добавляем им оси */
for (qint32 sCounter = 0; sCounter < m_sensors->count(); sCounter++)
{
chart->addSeries(line);
chart->attachAxis(axisY);
}

Начальная вставка данных:

Код:
line->append(i, v);
/* При необходимости расширяем диапазон оси Y */
if (v < axisY->min())
{
axisY->setMin(v);
}
else
{
if (v > axisY->max())
{
axisY-> setMax(v);
}
}

Добавление нового отсчета:
Код:
/* Вставляем заданное значение */
line->insert(0, QPointF(line->at(0).x() - 1, v));
line->remove(line->count() - 1);
axisX->setMax(axisX->max().addSecs(1));
axisX->setMin(axisX->min().addSecs(1));

/* Сдвигаем область отрисовки на один отсчет */
chart->scroll(-static_cast<double>(chart->plotArea().width()) /
  static_cast<double>(line->count()),
  0.0);

Добавление отсчетов происходит при вызова таймера, в отдельном потоке. Начальная загрузка записей где-то 500 мс, добавление записи около 10 мс. В общем все работает, но есть две проблемы:
1. Если эти две строки
Код:
line->insert(0, QPointF(line->at(0).x() - 1, v));
line->remove(line->count() - 1);
поменять местами, то программа начинает крашиться (вроде бы только при большом количестве отсчетов), "ASSERT failure in QVector<T>::operator[]: "index out of range"".
2. Во время добавления отсчета окно программы подвисает. Как при большом количестве отсчетов (18000), и так и при малом (300, фризит чуть меньше). Пробовал перемещать добавление точек в поток GUI - не помогает.
С окнами Qt особо не работал, может не так делаю? Повторюсь, задача - грузить большой массив отсчетов и обновлять его в процессе работы программы.


Название: Re: QChart - проблемы с обновлением списка
Отправлено: ViTech от Декабрь 12, 2018, 15:05
Добавление отсчетов происходит при вызова таймера, в отдельном потоке. Начальная загрузка записей где-то 500 мс, добавление записи около 10 мс. В общем все работает, но есть две проблемы:
1. Если эти две строки
Код:
line->insert(0, QPointF(line->at(0).x() - 1, v));
line->remove(line->count() - 1);
поменять местами, то программа начинает крашиться (вроде бы только при большом количестве отсчетов), "ASSERT failure in QVector<T>::operator[]: "index out of range"".
2. Во время добавления отсчета окно программы подвисает. Как при большом количестве отсчетов (18000), и так и при малом (300, фризит чуть меньше). Пробовал перемещать добавление точек в поток GUI - не помогает.
С окнами Qt особо не работал, может не так делаю? Повторюсь, задача - грузить большой массив отсчетов и обновлять его в процессе работы программы.

Есть вероятность, что QChart сама по себе тормозная и глючная штука. Я в том смысле, что не обязательно проблема в вашем коде. Возможно, придётся вам поэкспериментровать, чтобы подобрать способ взаимодействия с QChart, который не сильно тормозит. Ну и профилировщик и отладчик в помощь :).


Название: Re: QChart - проблемы с обновлением списка
Отправлено: Igors от Декабрь 12, 2018, 15:33
2. Во время добавления отсчета окно программы подвисает. Как при большом количестве отсчетов (18000), и так и при малом (300, фризит чуть меньше). Пробовал перемещать добавление точек в поток GUI - не помогает.
С окнами Qt особо не работал, может не так делаю? Повторюсь, задача - грузить большой массив отсчетов и обновлять его в процессе работы программы.
Так Вы 18000 (или 300) в цикле вставляете? Ну так не годится, нужно это делать одной вставкой


Название: Re: QChart - проблемы с обновлением списка
Отправлено: PazDim от Декабрь 12, 2018, 16:14
Так Вы 18000 (или 300) в цикле вставляете? Ну так не годится, нужно это делать одной вставкой
Спасибо, подумаю. Делаю это до добавления в QChart, заполнение трех графиков по 18000 занимает половину секунды (а то и меньше, там вроде часть времени уходит на получение данных из базы). А по основным проблемам?


Название: Re: QChart - проблемы с обновлением списка
Отправлено: PazDim от Декабрь 12, 2018, 21:04
Но если перенести таймер в основной поток (GUI), то вылетов нет.


Название: Re: QChart - проблемы с обновлением списка
Отправлено: ssoft от Декабрь 12, 2018, 22:21
Программа начинает крешится из-за одновременного конкурентного доступа к переменным line, axisX, chart и т.п. из двух потоков.
1. Можно было бы использовать средства синхронизации, но QObject'ы особенно чувствительны к доступу из потока, с которым они не связаны.
2. Вставка по одной точке не эффективна, вставляйте точки группами.

Возможен следующий сценарий.

Использовать для передачи точек из второго потока в первый очередь с блокировкой

Код
C++ (Qt)
QMutex m_mutex;
QQueue< Point > m_points;
 

В потоке, добавляющем данные, блокировать мютекс; добавлять данные в очередь; разблокировать мютекс; испускать сигнал emit dataIsReady();
В потоке отображения обрабатывать сигнал слотом onDataIsReady(), где блокировать мютекс; вычитывать сразу из очереди всё, что есть; разблокировать мютекс; добавлять вычитанные данные  график.


Название: Re: QChart - проблемы с обновлением списка
Отправлено: PazDim от Декабрь 13, 2018, 00:25
Программа начинает крешится из-за одновременного конкурентного доступа к переменным line, axisX, chart и т.п. из двух потоков.
1. Можно было бы использовать средства синхронизации, но QObject'ы особенно чувствительны к доступу из потока, с которым они не связаны.
2. Вставка по одной точке не эффективна, вставляйте точки группами.
Решается проблема с вылетами. А по поводу фризов? Даже если буду несколько секунд копить и потом кучей вставлять, то будет фризить каждые несколько секунд. Неужели сам модуль медленно работает?


Название: Re: QChart - проблемы с обновлением списка
Отправлено: kuzulis от Декабрь 13, 2018, 11:00
> Неужели сам модуль медленно работает?

Добро пожаловать в реальный мир Qt.

1. QtCharts не лучший вариант, если ты хочешь отрисовать графики с использованием QtWidgets. Я, например, везде использую Qwt и рад до усрачки.
2. Не используй потоки, если не знаешь как ими пользоваться и нужны ли они вообще? (тем более, таймером в потоке.. это жесть).


Название: Re: QChart - проблемы с обновлением списка
Отправлено: PazDim от Декабрь 13, 2018, 12:06
> Неужели сам модуль медленно работает?

Добро пожаловать в реальный мир Qt.

1. QtCharts не лучший вариант, если ты хочешь отрисовать графики с использованием QtWidgets. Я, например, везде использую Qwt и рад до усрачки.
2. Не используй потоки, если не знаешь как ими пользоваться и нужны ли они вообще? (тем более, таймером в потоке.. это жесть).
1. Спасибо, гляну. Бесплатный? Умеет динамически менять график? От мыши умеет принимать события? Рисовать дополнительную графику (текст, заполненные области)?
2. Таймер не только добавляет отсчет в график, но и отправляет данные в БД. Занимает это дело около 200 мс. Весь GUI поток в момент отправки данных фризит. Собственно, вынесение таймера в отдельный поток проблему решило. А как иначе использовать потоки? Читал, что переопределять метод run плохо, думал весь смысл - создать поток и привязать к нему слоты.


Название: Re: QChart - проблемы с обновлением списка
Отправлено: ViTech от Декабрь 13, 2018, 12:24
Я, например, везде использую Qwt и рад до усрачки.

Stable release 6.1.3 / June 13, 2016; 2 years ago

Не пользовался, но интересно: эта библиотека достигла совершенства или на неё забили?


Название: Re: QChart - проблемы с обновлением списка
Отправлено: kuzulis от Декабрь 13, 2018, 12:32
Цитировать
1. Спасибо, гляну. Бесплатный? Умеет динамически менять график? От мыши умеет принимать события? Рисовать дополнительную графику (текст, заполненные области)?

Конечно, и в отличии от QtCharts, у Qwt более мягкая лицензия на основе LGPLv3 с оговоркой о том, что ты можешь юзать Qwt как тебе хочется, только указывай в комментах к своей программе что ты юзаешь Qwt. Кроме того есть "оффициальная" ветка на форуме qtcentre.org где сам автор (Uwe) помогает с решением разного рода проблем.

Цитировать
Таймер не только добавляет отсчет в график, но и отправляет данные в БД.

Дык само АПИ доступа к БД вынеси в отдельный поток, сделав его псевдо-асинхронным. Например при помощи QFuture && QFutureWatcher (так проще, хотя и не идеально). Т.е. послал запрос в базу через QFuture... И ничего не блокируя делаешь что-то еще... Когда QFuture завершится, оно пошлет тебе сигнал... Сигнал пришел, поймал его и вытащил из QFuture данные с точками. Все!


Название: Re: QChart - проблемы с обновлением списка
Отправлено: kuzulis от Декабрь 13, 2018, 12:36
> Stable release 6.1.3 / June 13, 2016; 2 years ago

У тебя инфа устарела... Я юзаю к примеру "6.3.0". :)

Там все стабильно, что из транка, что из бранчей.. Кроме того там есть бранч multiaxes, где можно кучу осей добавтять на график.


Название: Re: QChart - проблемы с обновлением списка
Отправлено: ViTech от Декабрь 13, 2018, 12:52
> Stable release 6.1.3 / June 13, 2016; 2 years ago

У тебя инфа устарела... Я юзаю к примеру "6.3.0". :)

Там все стабильно, что из транка, что из бранчей.. Кроме того там есть бранч multiaxes, где можно кучу осей добавтять на график.

Ну это не у меня, а то, на что поиск выводит: Wikipedia (https://en.wikipedia.org/wiki/Qwt), SourceForge (https://sourceforge.net/projects/qwt/files/). Найти транк и воспользоваться им смогут не только лишь все :).