Qt/C++ — Урок 071. Динамическое создание графиков с QtCharts.

Разберём вариант создания графиков, когда необходимо добавлять большое количество графиков, которые создаются динамически. Подобный урок уже был в статье по динамическому созданию виджетов, только там добавлялись кнопки QPushButton . Здесь применяется тот же самый вариант работы. Выделяется память в куче, производится настройка виджета с графиком, и виджет добавляет в QScrollArea или QLayout, чтобы отобразить сам график в окне приложения. Приложение будет выглядеть следующим образом: В данном примере будет добавляться 5 графиков в горизонтальный Layout ( QHBoxLayout ). Также в примере будет добавлена всплывающая подсказка, которая содержит некоторую информацию. Например, номер графика и количество отсчётов.
Структура проекта
- Graphs.pro — профайл проекта;
- widget.h — заголовочный файл окна приложения;
- widget.cpp — файл исходных кодов окна приложения;
- widget.ui — форма окна приложения;
- main.cpp — файл с main функцией.
main.cpp создаётся по умолчанию и не изменяется в проекте. В файле widget.ui необходимо только создать размещение QHBoxLayout . Сделать это можно через графический дизайнер Qt.
В профайле проекта необходимо подключить модуль charts (он должен быть предварительно установлен, в виде предкомпилированных библиотек QtCharts доступен с версии Qt5.7).
QT += chartsВ заголовочном файле widget.h не производится никаких дополнительных изменений. Весь код будет содержаться в файле widget.cpp.
widget.h
#ifndef WIDGET_H #define WIDGET_H #include namespace Ui < class Widget; >class Widget : public QWidget < Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private: Ui::Widget *ui; >; #endif // WIDGET_Hwidget.cpp
#include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include static int randomBetween(int low, int high, int seed) < qsrand(seed); // Установка базового числа для отсчёта рандома в qrand return (qrand() % ((high + 1) - low) + low); >using namespace QtCharts; Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) < ui->setupUi(this); // Инициализирующее число для установки базы рандома в qrand int seed = 0; for (int i = 0; i < 5; ++i) < // Создаём представление графика QChartView *chartView = new QChartView(this); // Добавляем его в горизонтальный Layout ui->horizontalLayout->addWidget(chartView); // Создаём случайную синусоиду seed = randomBetween(0, 100, seed); QLineSeries *series = new QLineSeries(); int k = 0; while (k // Создаём график и добавляем в него синусоиду QChart *chart = new QChart(); chart->addSeries(series); chart->legend()->hide(); chart->setTitle("Graphic"); // Добавим всплывающую подсказку для графика chart->setToolTip(QString("График №%1\n" "Количество отсчётов %2").arg(i + 1).arg(k)); // Настройка осей графика QValueAxis *axisX = new QValueAxis(); axisX->setTitleText("x, м"); axisX->setLabelFormat("%i"); axisX->setTickCount(1); chart->addAxis(axisX, Qt::AlignBottom); series->attachAxis(axisX); QValueAxis *axisY = new QValueAxis(); axisY->setTitleText("t, мс"); axisY->setLabelFormat("%g"); axisY->setTickCount(5); chart->addAxis(axisY, Qt::AlignLeft); series->attachAxis(axisY); // Устанавливаем график в представление chartView->setChart(chart); > > Widget::~Widget()
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.
Рекомендуемые статьи по этой тематике
- Qt/C++ - Урок 031. QCustomPlot - строим график по времени
- Qt/C++ - Урок 032. Сохранение изображения в файл из QCustomPlot
- Qt/C++ - Урок 030. QCustomPlot - быстрый старт в работе с графиками
- Qt/C++ - Урок 014. Динамическое создание виджетов в Qt
По статье задано0 вопрос(ов)
Подписка на обсуждение 4
Подписка на раздел 343
Вам это нравится? Поделитесь в социальных сетях!
В поддержку Qt
Нетрудно представить практическую задачу, при решении которой потребуется синхронизация горизонтальной оси (как правило, это ось времени) нескольких графиков. Это означает, что если изменяется масштаб на одном из графиков, немедленно должен измениться масштаб горизонтальной оси всех остальных графиков, синхронизированных с ним.
В ранее опубликованной статье рассмотрен класс QwtChartZoom , обеспечивающий интерфейс масштабирования и перемещения графика QwtPlot в стиле TChart из библиотеки компонентов Delphi и C++Builder. Напомню, что выделение области, определяющей новые границы графика, в этом интерфейсе производится левой кнопкой мыши движением слева направо и сверху вниз. При отпускании левой кнопкой мыши график изменяет свой масштаб. Если попытаться выделить область в противоположном направлении, то при отпускании кнопки мыши границы графика вернутся к исходному состоянию. Перемещение графика (причем в любом направлении) производится при нажатой правой кнопке мыши.
Класс QwtChartZoom и его дополнения был взят за основу при разработке интерфейса синхронного масштабирования нескольких графиков. Разработанный класс получил название QChartSynZoom . Кроме того, имеется два класса QWheelSynZoomSvc и QAxisSynZoomSvc , выполняющие ту же функцию, что и аналогичные дополнения к классу QwtChartZoom . Первый поддерживает изменение масштаба вращением колеса мыши при нажатой клавише или . Если нажата клавиша , то масштабирование производится и по вертикольной оси, и по горизонтальной. Если нажат левый , то изменяется масштаб только по вертикальной шкале, если правый , только по горизонтальной. Второй класс QAxisSynZoomSvc позволяет изменять одну из границ шкалы, путем ее перетаскивания мышью.
Следует отметить, что на класс QChartSynZoom кроме синхронного изменения границ горизонтальной шкалы графиков возложена подгонка ширины виджетов, на которых изображаются вертикальная шкала слева и справа от графиков, так чтобы границы канвы всех графиков совпадали. Если метки, нанесенные на вертикальную шкалу какого-либо графика, требуют для прорисовки меньше места, чем метки на аналогичной шкале других графиков, то ширина виджета этой шкалы должна быть принудительно увеличена до требуемого размера. Эту ситуацию иллюстрирует рисунок
Поскольку графики с синхронизированной горизонтальной шкалой должны располагаться один под другим, то хорошей, но необязательной к исполнению, идеей является поместить графики в контейнер QSplitter . Класс QChartSynZoom имеет вариант конструктора, в котором указатель на QSplitter присутствует в качестве аргумента. Это дает возможность интерфейсу масштабирования отслеживать дополнительные события от контейнера и корректно настраивать вид графиков. К сожалению в дизайнере форм в палитре компонентов отсутствует QSplitter , поэтому прописывать его в файл формы *.ui приходится вручную. О том, как это сделать, можно прочитать здесь.
Порядок подключения интерфейса QwtChartSynZoom не сильно отличается от порядка подключения QwtChartZoom , поэтому дальнейшие инструкции во многом повторяют приведенные в вышеупомянутой статье.
Пусть на форме главного окна приложения имеется контейнер QSplitter , а в нем размещены 3 графика с именами plot1 , plot2 и plot3 . (Как уже отмечалось, использовать QSplitter не обязательно.) Ниже приведены заголовочный файл и файл реализации класса MainWindow .
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
Место для размещения дополнительных директив #include
namespace Ui class MainWindow ;
>
class MainWindow : public QMainWindow Q_OBJECT
public :
MainWindow ( QWidget *parent = 0 );
~MainWindow();
private :
Ui :: MainWindow * ui ;
Место для размещения для указатей на элементы графика, менеджер масштабирования и его дополнения
>
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow :: MainWindow ( QWidget *parent) :
QMainWindow (parent),
ui ( new Ui :: MainWindow )
ui ->setupUi( this );
Место для размещения инструкций наполнения графика, подключения менеджера масштабирования и его дополнений
MainWindow ::~MainWindow()
Место для размещения инструкций удаления менеджера масштабирования, его дополнений и элементов графика
Если форма разрабатывалась с помощью Qt Designer, то класс MainWindow определен в пространстве имен Ui , и доступ ко всем элементам формы осуществляется через указатель ui : например, ui->plot1 . Пустые графики создаются при выполнении инструкции ui->setupUi(this) в конструкторе главного окна приложения. Далее следует наполнение графиков: создаются кривые с данными, устанавливаются свойства шкал и т.п. (пример оформления графика приведен в посвященной этому вопросу статье). После перестроения графиков здесь же в конструкторе создается менеджер синхронного масштабирования экземпляр класса QChartSynZoom вместе с дополнениями QWheelSynZoomSvc и QAxisSynZoomSvc . Понятно, что в свой проект надо добавить файлы, реализующие эти классы. В деструкторе перед удалением объектов из пространства имен Ui командой delete ui сначала удаляются менеджер масштабирования и его дополнения, а также все элементы графика, созданные в конструкторе командой new . Для того чтобы иметь доступ к этим элементам в деструкторе, указатели на них должны являться членами класса MainWindow и быть объявленными в заголовочном файле.
Таким образом, последовательность подключения интерфейса QChartSynZoom следующая
1. Копируем в папку со своим проектом файлы "qchartsynzoom.h" , "qchartsynzoom.cpp" , "qwheelsynzoomsvc.h" , "qwheelsynzoomsvc.cpp" , "qaxissynzoomsvc.h" и "qaxissynzoomsvc.cpp" , которые доступны по ссылке. Если какое-то из дополений QWheelSynZoomSvc или QAxisSynZoomSvc не планируется использовать в проекте, то понятно, что файлы этого класса копировать не надо.
2. Добавляем скопированные файлы в свой проект
SOURCES += qchartsynzoom.cpp\
qwheelsynzoomsvc.cpp\
qaxissynzoomsvc.cpp
HEADERS += qchartsynzoom.h\
qwheelsynzoomsvc.h\
qaxissynzoomsvc.h
Опять же, заголовочные файлы и файлы исходного кода классов QWheelSynZoomSvc и QAxisSynZoomSvc необходимо добавлять в проект только в том случае, если запланировано их использовать.
3. В заголовочный файл "mainwindow.h" включаем дополнительные директивы #include
#include "qchartsynzoom.h"
#include "qwheelsynzoomsvc.h" (если надо)
#include "qaxissynzoomsvc.h" (если надо)
4. В секции private объявляем указатели на менеджер масштабирования и перемещения графика
и его дополнения
QWheelSynZoomSvc * whlzmsvc ; (если надо)
QAxisSynZoomSvc * axzmsvc ; (если надо)
5. В конструкторе главного окна приложения (файл "mainwindow.cpp" ) создаем экземпляр класса QChartSynZoom , и, если необходимо, переопределяем цвет каймы выделяемой области, задающей новый масштаб графика
zoom = new QChartSynZoom ( ui -> splitter );
zoom ->setRubberBandColor( Qt :: white );
Обратите внимание на то, что указатель на контейнер QSplitter присутствует в качестве аргумента в конструкторе. Как уже отмечалось, это дает возможность интерфейсу масштабирования отслеживать дополнительные события от него и корректно настраивать вид графиков. Если же класс QSplitter не используется, и графики выровнены один под другим с помощью иных средств, то экземпляр класса QChartSynZoom создается без указания аргумента
zoom = new QChartSynZoom ();
Далее графики отдаются под опеку менеджера масштабирования с помощью вызова функции appendPlot()
zoom ->appendPlot( ui -> plot1 );
zoom ->appendPlot( ui -> plot2 );
zoom ->appendPlot( ui -> plot3 );
Здесь же, если запланировано, создаем экземпляр класса QWheelSynZoomSvc , и прикрепляем его к менеджеру масштабирования
whlzmsvc = new QWheelSynZoomSvc ();
whlzmsvc ->attach( zoom );
Далее, если запланировано, создаем экземпляр класса QAxisSynZoomSvc , и прикрепляем его к менеджеру масштабирования
axzmsvc = new QAxisSynZoomSvc ();
axzmsvc ->attach( zoom );
6. В деструктор вставляем команды удаления объектов
delete axzmsvc ; (если надо)
delete whlzmsvc ; (если надо)
delete zoom ;
Готовый проект с подключенным интерфейсом доступен по ссылке. Проект, в котором не используется QSplitter , можно взять здесь. Для дополнительной демонстрации в интерфейсе масштабирования в этом проекте включен "легкий" режим.
Перечислим имеющиеся функции управления интерфейсом и его дополнениями
void QChartSynZoom ::appendPlot( QwtPlot )
Добавляет под опеку график. Количество опекаемых графиков ограничено только вертикальным размером экрана.
void QChartSynZoom ::fixBoundaries()
Фиксирует текущие границы графика в качестве исходных. Отмена масштабирования будет возвращать график имеено к этим границам.
void QChartSynZoom ::setRubberBandColor( QColor )
Устанавливает цвет каймы выделяемой области, задающей новый размер графика, (по умолчанию черный).
void QChartSynZoom ::setLightMode( bool )
Включает/выключает "легкий" режим перемещения графика (по умолчанию выключен).
void QChart Syn Zoom ::indicateDragBand( QChart Syn Zoom :: QDragIndiStyle )
Задает стиль индикатора перемещения графика в "легком" режиме. Аргумент может принимать значения
QChartSynZoom::disNone индикация отключена;
QChartSynZoom::disSimple упрощенная индикация;
QChartSynZoom::disDetailed подробная индикация.
(По умолчанию задан стиль QChartSynZoom::disSimple .)
void QwtChartSynZoom ::setDragBandColor( QColor )
Устанавливает цвет индикатора перемещения графика в "легком" режиме (по умолчанию черный).
void QWheelSynZoomSvc ::attach( QChartSynZoom * )
Подключает дополнение QWheelSynZoomSvc к интерфейсу масштабирования.
void QWheelSynZoomSvc ::setWheelFactor( double )
Задает коэффициент масштабирования графика при вращении колеса мыши (по умолчанию коэффициент равен 1.2).
void QAxisSynZoomSvc ::attach( QChartSynZoom * )
Подключает дополнение QAxisSynZoomSvc к интерфейсу масштабирования.
void QAxisSynZoomSvc ::setLightMode( bool )
Включает/выключает "легкий" режим изменения границы шкалы (по умолчанию выключен).
void QAxisSynZoomSvc ::indicateDragBand( bool )
Включает/выключает индикацию изменения границы шкалы в "легком" режиме (по умолчанию индикация включена).
void QAxisSynZoomSvc ::setAxisRubberBandColor( QColor )
Устанавливает цвет индикатора изменения границы шкалы в "легком" режиме (по умолчанию черный).
Как видим, для работы на слабых компьютерах предусмотрен "легкий" режим интерфейса, подобно тому, как это реализовано для класса QChartSynZoom .
Замечание. Если под опеку синхронного менеджера масштабирования добавить всего один график, то внешне все будет выглядеть также как и при использовании класса QwtChartZoom . Более того, опекаемый график можно указать в качестве аргумента непосредственно в при создании экземпляра класса QChartSynZoom , например так
zoom = new QChartSynZoom ( ui -> myPlot );
Таким образом, класс QwtChartZoom сохраняет право на существование только для того, чтобы сэкономить размер генерируемого кода.
Автоматическая подстройка диапазона оси значений QValueAxis на гистограммах Qt Charts
Часто в разработке реальных приложений точный диапазон значений, которые необходимо вывести на гистограмму, бывает заранее неизвестен. Максимальные ожидаемые значения могут различаться в десятки и сотни раз. Поэтому установка шкал значений на гистограмме в какое-то предельно максимальное значение будет не лучшим решением – пострадает наглядность представления данных при выводе малых значений, по крайней мере, до выполнения пользователем ручной настройки шкалы.
В данной статье рассматривается, как автоматически изменять диапазон оси значений QValueAxis на гистограмме Qt Charts, исходя из значений, принимаемых наборами полос (объектами QBarset ) из модели данных.
Пример автоматической подстройки диапазона оси значений QValueAxis
В данном примере на гистограмме выводятся получаемые из модели BitrateTableModel данные о скоростях элементарных потоков (в кбит/с).
Элементарные потоки со значениями PID, заканчивающимися на единицу, – это потоки видео. В момент запуска приложения их скорости составляют 2650-2750 кбит/с, а через 5 секунд после запуска их скорости увеличиваются до 7600-7700 кбит/с. Подстройка шкалы оси значений происходит в первый раз в момент запуска приложения и второй раз в момент изменения скоростей видеопотоков.
Создание диаграммы
Для простоты всё создание диаграммы выполним в конструкторе объекта класса, который наследуется от QMainWindow .
Процесс создания гистограммы практически аналогичен примеру, приведенному в статье «Использование гистограмм Qt Charts совместно с моделями данных», за исключением того, что гистограмма данной статье будет использоваться горизонтальная, плюс добавилась обработка выводимых на ней значений. Поэтому некоторые подробности будут опущены.
Начнем с создания экземпляра класса BitrateTableModel . Класс BitrateTableModel является производным от QAbstractTableModel и был создан только для этого примера. Конструктор этого класса заполняет внутреннее хранилище данных модели данными, необходимыми для нашего примера работы с диаграммами. А после создания модель каждые 500 мс обновляет данные о скоростях элементарных потоков псевдослучайными значениями.
model = new BitrateTableModel;
Данные мы хотим отображать не только на гистограмме, но и в таблице (объекте QTableView ).
ui->tableView->setModel(model); ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); model->setParent(ui->tableView);
Теперь нам нужен экземпляр QChart для отображения на гистограмме тех же данных.
chart = new QChart;
Создаем новый объект последовательности полос QHorizontalBarSeries . Следующие три строки создают преобразователь данных, экземпляр класса QVBarModelMapper , и указывают, что данные для наборов полос должны быть взяты из столбца модели с индексом 1 (значение BitrateTableModel::ColumnBitrate ). Чтобы создать связь между последовательностью полос и моделью, передаем оба этих объекта преобразователю данных, т.е. объекту mapper класса QVBarModelMapper .
Наконец, добавляем к диаграмме последовательность полос series .
QHorizontalBarSeries *series = new QHorizontalBarSeries; mapper = new QVBarModelMapper(this); mapper->setFirstBarSetColumn(BitrateTableModel::ColumnBitrate); mapper->setLastBarSetColumn(BitrateTableModel::ColumnBitrate); mapper->setSeries(series); mapper->setModel(model); chart->addSeries(series);
Также неплохо было бы, чтобы на оси диаграммы были подписаны категории, которые описывали бы суть данных. Категории в данном примере – это значения идентификаторов пакетов (PID) элементарных потоков, хранящиеся в модели BitrateTableModel в столбце 0 (значение BitrateTableModel::ColumnPid ). Следующий цикл сохраняет значения категорий в объект QStringList categories , плюс определяет максимальное текущее значение скорости, которое необходимо отобразить на гистограмме.
int rowCount = model->rowCount(); QStringList categories; qreal maxValue = 0; for(int i = 0; i < rowCount; ++i) < QModelIndex idx = model->index(i, BitrateTableModel::ColumnPid); categories data(idx).toString(); idx = model->index(i, BitrateTableModel::ColumnBitrate); qreal curValue = model->data(idx).toDouble(); if (curValue > maxValue) maxValue = curValue; >
Создаем ось категорий (объект QBarCategoryAxis ). Делаем ее линии сетки невидимыми и передаем ей сформированный список категорий. После чего добавляем ее на диаграмму (в этом случае она будет вертикальной, слева) и прикрепляем к последовательности полос.
QBarCategoryAxis *axisY = new QBarCategoryAxis(); axisY->setGridLineVisible(false); axisY->setLineVisible(false); axisY->append(categories); chart->addAxis(axisY, Qt::AlignLeft); series->attachAxis(axisY);
Создаем ось значений (объект QValueAxis ). Добавляем ее на диаграмму (она будет горизонтальной, внизу) и тоже прикрепляем к последовательности полос. После чего по определенному ранее максимальному значению, которое будет выведено на гистограмме, устанавливаем максимальное значение шкалы оси. Функция setAxisXMaxFromVal() , выполняющая эту задачу, будет описана ниже.
QValueAxis *axisX = new QValueAxis(); chart->addAxis(axisX, Qt::AlignBottom); series->attachAxis(axisX); setAxisXMaxFromVal(maxValue, axisX);
Но нам необходимо, чтобы шкала оси значений QValueAxis подстраивалась автоматически не только в момент запуска, но и во время работы приложения, поскольку скорости предполагаемых элементарных потоков могут внезапно достаточно сильно увеличиться. Для этого мы будем обрабатывать изменения значений каждой выводимой на гистограмме полосы, т.е. каждой полосы в каждом объекте QBarSet .
В следующем фрагменте кода мы получаем все объекты QBarSet в нашей последовательности (так как мы выводим на диаграмму только один столбец модели, то в нашем случае объект QBarSet будет всего один) и к сигналу valueChanged(int index) каждого из них привязываем слот processBarSetValueChange(int index) , обрабатывающий изменения значений.
QList barsets = series->barSets(); for(int i = 0; i
Чтобы избежать настройки QGraphicsScene , мы используем класс QChartView , который делает это за нас. Указатель на объект QChart используется как параметр конструктора QChartView . Чтобы визуализация выглядела лучше, включаем антиалиасинг и устанавливаем минимальный размер виджета chartView .
chartView = new QChartView(chart); chartView->setRenderHint(QPainter::Antialiasing); chartView->setMinimumSize(640, 480);
И, наконец, помещаем виджет chartView в специально подготовленный в дизайнере виджет QGroupBox .
ui->chartGroupBox->layout()->addWidget(chartView);
Подстройка верхнего предела шкалы оси значений
Проверка необходимости изменения размера шкалы оси значений во время работы приложения выполняется в слоте processBarSetValueChange(int index) , который ранее был привязан к сигналам valueChanged(int index) объектов QBarSet .
Здесь мы находим нашу ось значений QValueAxis , сравниваем ее максимальное значение с полученным измененным значением объекта QBarSet , выдавшего сигнал, и при необходимости изменяем верхний предел шкалы оси с помощью функции setAxisXMaxFromVal() .
void MainWindow::processBarSetValueChange(int index) < QListhAxises = chart->axes(Qt::Horizontal); if(hAxises.isEmpty()) return; QValueAxis *axisX = qobject_cast(hAxises.at(0)); QBarSet *barset = qobject_cast(sender()); qreal value = barset->at(index); if (value > axisX->max()) setAxisXMaxFromVal(value, axisX); >
Изменение верхнего предела шкалы оси значений выполняется в функции setAxisXMaxFromVal() . Для удобства пользователя в зависимости от максимального отображаемого значения выбираем верхний предел шкалы из ряда 5, 10, 50, 100, 500, 1000 и т.д. И устанавливаем определенное значение в качестве предельного значения шкалы оси значений QValueAxis .
void MainWindow::setAxisXMaxFromVal(double val, QValueAxis *axis) < int degree = (int)floor(log10(abs(val))); int scaled = val * pow(10, -degree); int step2 = ((scaled +4)/5)*5; int maxValue = step2 * pow(10, degree); axis->setMax(maxValue); >
В результате получаем приложение следующего вида. Первый скриншот – сразу после запуска, второй – через 5 секунд.


Исходный код
Полный исходный код проекта доступен на GitHub.
Также ниже приведен код исходного файлов mainwindow.cpp и mainwindow.h .
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include "bitratetablemodel.h" #include #include QT_CHARTS_USE_NAMESPACE QT_BEGIN_NAMESPACE namespace Ui < class MainWindow; >QT_END_NAMESPACE class MainWindow : public QMainWindow < Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); public slots: void processBarSetValueChange(int index); void setAxisXMaxFromVal(double val, QValueAxis *axis); private: Ui::MainWindow *ui; BitrateTableModel *model; QVBarModelMapper *mapper; QChart *chart; QChartView *chartView; >; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include //--------------------------------------------------------------------------------------- MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) < ui->setupUi(this); model = new BitrateTableModel; ui->tableView->setModel(model); ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); model->setParent(ui->tableView); chart = new QChart; QHorizontalBarSeries *series = new QHorizontalBarSeries; mapper = new QVBarModelMapper(this); mapper->setFirstBarSetColumn(BitrateTableModel::ColumnBitrate); mapper->setLastBarSetColumn(BitrateTableModel::ColumnBitrate); mapper->setSeries(series); mapper->setModel(model); chart->addSeries(series); int rowCount = model->rowCount(); QStringList categories; qreal maxValue = 0; for(int i = 0; i < rowCount; ++i) < QModelIndex idx = model->index(i, BitrateTableModel::ColumnPid); categories data(idx).toString(); idx = model->index(i, BitrateTableModel::ColumnBitrate); qreal curValue = model->data(idx).toDouble(); if (curValue > maxValue) maxValue = curValue; > QBarCategoryAxis *axisY = new QBarCategoryAxis(); axisY->setGridLineVisible(false); axisY->setLineVisible(false); axisY->append(categories); chart->addAxis(axisY, Qt::AlignLeft); series->attachAxis(axisY); QValueAxis *axisX = new QValueAxis(); chart->addAxis(axisX, Qt::AlignBottom); series->attachAxis(axisX); setAxisXMaxFromVal(maxValue, axisX); QList barsets = series->barSets(); for(int i = 0; i < barsets.size(); ++i) < connect(barsets.at(i), &QBarSet::valueChanged, this, &MainWindow::processBarSetValueChange); >chartView = new QChartView(chart); chartView->setRenderHint(QPainter::Antialiasing); chartView->setMinimumSize(640, 480); ui->chartGroupBox->layout()->addWidget(chartView); > //--------------------------------------------------------------------------------------- MainWindow::~MainWindow() < delete ui; >//--------------------------------------------------------------------------------------- void MainWindow::processBarSetValueChange(int index) < QListhAxises = chart->axes(Qt::Horizontal); if(hAxises.isEmpty()) return; QValueAxis *axisX = qobject_cast(hAxises.at(0)); QBarSet *barset = qobject_cast(sender()); qreal value = barset->at(index); if (value > axisX->max()) setAxisXMaxFromVal(value, axisX); > //--------------------------------------------------------------------------------------- void MainWindow::setAxisXMaxFromVal(double val, QValueAxis *axis) < int degree = (int)floor(log10(abs(val))); int scaled = val * pow(10, -degree); int step2 = ((scaled +4)/5)*5; int maxValue = step2 * pow(10, degree); axis->setMax(maxValue); > //---------------------------------------------------------------------------------------
Теги
Сохранить или поделиться
На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.
В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.
QChartView Class
A chart view does not require a QGraphicsScene object to work. To display a chart in an existing QGraphicsScene, the QChart or QPolarChart class should be used instead.
Member Type Documentation
[since 6.2] enum QChartView:: RubberBand
flags QChartView:: RubberBands
This enum describes the different types of rubber band effects that can be applied to the rectangular zooming area.
| Constant | Value | Description |
|---|---|---|
| QChartView::NoRubberBand | 0x0 | No zooming area is specified, and therefore zooming is not enabled. |
| QChartView::VerticalRubberBand | 0x1 | The rubber band is locked to the size of the chart horizontally and can be pulled vertically to specify the zooming area. |
| QChartView::HorizontalRubberBand | 0x2 | The rubber band is locked to the size of the chart vertically and can be pulled horizontally to specify the zooming area. |
| QChartView::RectangleRubberBand | 0x3 | The rubber band is fixed to the point that was clicked and can be pulled both vertically and horizontally. |
| QChartView::ClickThroughRubberBand | 0x80 | An option on the above rubber band choices that allows left clicks to be passed on to chart items if those chart items accept clicks. To select this, OR it with one of the rubber band selection modes. |
This enum was introduced in Qt 6.2.
The RubberBands type is a typedef for QFlags. It stores an OR combination of RubberBand values.
Member Function Documentation
[explicit] QChartView:: QChartView ( QWidget *parent = nullptr)
Constructs a chart view object with the parent parent.
[explicit] QChartView:: QChartView ( QChart *chart, QWidget *parent = nullptr)
Constructs a chart view object with the parent parent to display the chart chart. The ownership of the chart is passed to the chart view.
[virtual noexcept] QChartView:: ~QChartView ()
Deletes the chart view object and the associated chart.
QChart *QChartView:: chart () const
Returns the pointer to the associated chart.
[override virtual protected] void QChartView:: mouseMoveEvent ( QMouseEvent *event)
If the rubber band rectangle is displayed in the press event specified by event, the event data is used to update the rubber band geometry. Otherwise, the default QGraphicsView::mouseMoveEvent() implementation is called.
[override virtual protected] void QChartView:: mousePressEvent ( QMouseEvent *event)
If the left mouse button is pressed and the rubber band is enabled, the event event is accepted and the rubber band is displayed on the screen. This enables the user to select the zoom area.
If some other mouse button is pressed or the rubber band is disabled, the event is passed to QGraphicsView::mousePressEvent().
[override virtual protected] void QChartView:: mouseReleaseEvent ( QMouseEvent *event)
If the left mouse button is released and the rubber band is enabled, the event event is accepted and the view is zoomed into the rectangle specified by the rubber band. If releasing the right mouse button triggered the event, the view is zoomed out.
[override virtual protected] void QChartView:: resizeEvent ( QResizeEvent *event)
Resizes and updates the chart area using the data specified by event.
QChartView::RubberBands QChartView:: rubberBand () const
Returns the rubber band flags that are currently being used by the chart view.
void QChartView:: setChart ( QChart *chart)
Sets the current chart to chart. The ownership of the new chart is passed to the chart view and the ownership of the previous chart is released.
To avoid memory leaks, the previous chart must be deleted.
void QChartView:: setRubberBand (const QChartView::RubberBands &rubberBand)
Sets the rubber band flags to rubberBand. The selected flags determine the way zooming is performed.
Note: Rubber band zooming is not supported for polar charts.
© 2023 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.

