Russian Qt Forum
Ноябрь 22, 2024, 11:50 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: QChart - проблемы с обновлением списка  (Прочитано 8983 раз)
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 особо не работал, может не так делаю? Повторюсь, задача - грузить большой массив отсчетов и обновлять его в процессе работы программы.
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #1 : Декабрь 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, который не сильно тормозит. Ну и профилировщик и отладчик в помощь Улыбающийся.
Записан

Пока сам не сделаешь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Декабрь 12, 2018, 15:33 »

2. Во время добавления отсчета окно программы подвисает. Как при большом количестве отсчетов (18000), и так и при малом (300, фризит чуть меньше). Пробовал перемещать добавление точек в поток GUI - не помогает.
С окнами Qt особо не работал, может не так делаю? Повторюсь, задача - грузить большой массив отсчетов и обновлять его в процессе работы программы.
Так Вы 18000 (или 300) в цикле вставляете? Ну так не годится, нужно это делать одной вставкой
Записан
PazDim
Гость
« Ответ #3 : Декабрь 12, 2018, 16:14 »

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

Но если перенести таймер в основной поток (GUI), то вылетов нет.
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #5 : Декабрь 12, 2018, 22:21 »

Программа начинает крешится из-за одновременного конкурентного доступа к переменным line, axisX, chart и т.п. из двух потоков.
1. Можно было бы использовать средства синхронизации, но QObject'ы особенно чувствительны к доступу из потока, с которым они не связаны.
2. Вставка по одной точке не эффективна, вставляйте точки группами.

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

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

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

В потоке, добавляющем данные, блокировать мютекс; добавлять данные в очередь; разблокировать мютекс; испускать сигнал emit dataIsReady();
В потоке отображения обрабатывать сигнал слотом onDataIsReady(), где блокировать мютекс; вычитывать сразу из очереди всё, что есть; разблокировать мютекс; добавлять вычитанные данные  график.
Записан
PazDim
Гость
« Ответ #6 : Декабрь 13, 2018, 00:25 »

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

Сообщений: 2812


Просмотр профиля
« Ответ #7 : Декабрь 13, 2018, 11:00 »

> Неужели сам модуль медленно работает?

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

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

ArchLinux x86_64 / Win10 64 bit
PazDim
Гость
« Ответ #8 : Декабрь 13, 2018, 12:06 »

> Неужели сам модуль медленно работает?

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

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

Сообщений: 858



Просмотр профиля
« Ответ #9 : Декабрь 13, 2018, 12:24 »

Я, например, везде использую Qwt и рад до усрачки.

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

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

Пока сам не сделаешь...
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #10 : Декабрь 13, 2018, 12:32 »

Цитировать
1. Спасибо, гляну. Бесплатный? Умеет динамически менять график? От мыши умеет принимать события? Рисовать дополнительную графику (текст, заполненные области)?

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

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

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

ArchLinux x86_64 / Win10 64 bit
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #11 : Декабрь 13, 2018, 12:36 »

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

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

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

ArchLinux x86_64 / Win10 64 bit
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #12 : Декабрь 13, 2018, 12:52 »

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

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

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

Ну это не у меня, а то, на что поиск выводит: Wikipedia, SourceForge. Найти транк и воспользоваться им смогут не только лишь все Улыбающийся.
Записан

Пока сам не сделаешь...
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.073 секунд. Запросов: 23.