mainwindow.cpp
526 lines
| 15.1 KiB
| text/x-c
|
CppLexer
|
r2854 | /**************************************************************************** | ||
|
r2834 | ** | ||
|
r2854 | ** Copyright (C) 2016 The Qt Company Ltd. | ||
** Contact: https://www.qt.io/licensing/ | ||||
|
r2834 | ** | ||
|
r2854 | ** This file is part of the Qt Charts module of the Qt Toolkit. | ||
|
r2834 | ** | ||
|
r2854 | ** $QT_BEGIN_LICENSE:GPL$ | ||
|
r2845 | ** Commercial License Usage | ||
** Licensees holding valid commercial Qt licenses may use this file in | ||||
** accordance with the commercial license agreement provided with the | ||||
** Software or, alternatively, in accordance with the terms contained in | ||||
** a written agreement between you and The Qt Company. For licensing terms | ||||
|
r2854 | ** and conditions see https://www.qt.io/terms-conditions. For further | ||
** information use the contact form at https://www.qt.io/contact-us. | ||||
** | ||||
** GNU General Public License Usage | ||||
** Alternatively, this file may be used under the terms of the GNU | ||||
** General Public License version 3 or (at your option) any later version | ||||
** approved by the KDE Free Qt Foundation. The licenses are as published by | ||||
** the Free Software Foundation and appearing in the file LICENSE.GPL3 | ||||
** included in the packaging of this file. Please review the following | ||||
** information to ensure the GNU General Public License requirements will | ||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html. | ||||
|
r2834 | ** | ||
|
r2845 | ** $QT_END_LICENSE$ | ||
** | ||||
|
r2854 | ****************************************************************************/ | ||
|
r2834 | |||
#include "mainwindow.h" | ||||
#include "chartview.h" | ||||
#include <QtCharts/QScatterSeries> | ||||
#include <QtCharts/QLineSeries> | ||||
#include <QtCharts/QValueAxis> | ||||
#include <QtCharts/QLogValueAxis> | ||||
#include <QtCharts/QDateTimeAxis> | ||||
#include <QtCharts/QCategoryAxis> | ||||
#include <QtCharts/QChart> | ||||
#include <QtCore/QDebug> | ||||
#include <QtCore/QDateTime> | ||||
QT_CHARTS_USE_NAMESPACE | ||||
#include "ui_mainwindow.h" | ||||
MainWindow::MainWindow(QWidget *parent) : | ||||
QMainWindow(parent), | ||||
ui(new Ui::MainWindow), | ||||
m_xMin(0.0), | ||||
m_xMax(20.0), | ||||
m_yMin(0.0), | ||||
m_yMax(10.0), | ||||
m_backgroundBrush(new QBrush(Qt::white)), | ||||
m_plotAreaBackgroundBrush(new QBrush(Qt::NoBrush)), | ||||
m_backgroundPen(new QPen(Qt::NoPen)), | ||||
m_plotAreaBackgroundPen(new QPen(Qt::NoPen)), | ||||
m_animationOptions(QChart::NoAnimation), | ||||
m_chart(0), | ||||
m_xAxis(0), | ||||
m_yAxis(0), | ||||
m_xAxisMode(AxisModeValue), | ||||
m_yAxisMode(AxisModeValue), | ||||
m_pointCount(100) | ||||
{ | ||||
ui->setupUi(this); | ||||
ui->yMinSpin->setValue(m_yMin); | ||||
ui->yMaxSpin->setValue(m_yMax); | ||||
ui->xMinSpin->setValue(m_xMin); | ||||
ui->xMaxSpin->setValue(m_xMax); | ||||
initXYValueChart(); | ||||
setXAxis(AxisModeValue); | ||||
setYAxis(AxisModeValue); | ||||
connect(ui->yMinSpin, SIGNAL(valueChanged(double)), | ||||
this, SLOT(yMinChanged(double))); | ||||
connect(ui->yMaxSpin, SIGNAL(valueChanged(double)), | ||||
this, SLOT(yMaxChanged(double))); | ||||
connect(ui->xMinSpin, SIGNAL(valueChanged(double)), | ||||
this, SLOT(xMinChanged(double))); | ||||
connect(ui->xMaxSpin, SIGNAL(valueChanged(double)), | ||||
this, SLOT(xMaxChanged(double))); | ||||
connect(ui->animationsComboBox, SIGNAL(currentIndexChanged(int)), | ||||
this, SLOT(animationIndexChanged(int))); | ||||
connect(ui->xAxisComboBox, SIGNAL(currentIndexChanged(int)), | ||||
this, SLOT(xAxisIndexChanged(int))); | ||||
connect(ui->yAxisComboBox, SIGNAL(currentIndexChanged(int)), | ||||
this, SLOT(yAxisIndexChanged(int))); | ||||
connect(ui->backgroundComboBox, SIGNAL(currentIndexChanged(int)), | ||||
this, SLOT(backgroundIndexChanged(int))); | ||||
connect(ui->plotAreaComboBox, SIGNAL(currentIndexChanged(int)), | ||||
this, SLOT(plotAreaIndexChanged(int))); | ||||
connect(ui->themeComboBox, SIGNAL(currentIndexChanged(int)), | ||||
this, SLOT(themeIndexChanged(int))); | ||||
connect(ui->addSeriesButton, SIGNAL(clicked(bool)), | ||||
this, SLOT(addSeriesClicked())); | ||||
connect(ui->addGLSeriesButton, SIGNAL(clicked(bool)), | ||||
this, SLOT(addGLSeriesClicked())); | ||||
connect(ui->removeSeriesButton, SIGNAL(clicked(bool)), | ||||
this, SLOT(removeSeriesClicked())); | ||||
connect(ui->countComboBox, SIGNAL(currentIndexChanged(int)), | ||||
this, SLOT(countIndexChanged(int))); | ||||
connect(ui->colorsComboBox, SIGNAL(currentIndexChanged(int)), | ||||
this, SLOT(colorIndexChanged(int))); | ||||
connect(ui->widthComboBox, SIGNAL(currentIndexChanged(int)), | ||||
this, SLOT(widthIndexChanged(int))); | ||||
ui->chartView->setChart(m_chart); | ||||
ui->chartView->setRenderHint(QPainter::Antialiasing); | ||||
QObject::connect(m_chart->scene(), &QGraphicsScene::changed, | ||||
&m_dataSource, &DataSource::handleSceneChanged); | ||||
m_dataSource.startUpdates(m_seriesList, ui->fpsLabel); | ||||
} | ||||
MainWindow::~MainWindow() | ||||
{ | ||||
delete ui; | ||||
} | ||||
void MainWindow::initXYValueChart() | ||||
{ | ||||
m_chart = new QChart(); | ||||
m_chart->setTitle("Use arrow keys to scroll and +/- to zoom"); | ||||
m_chart->setAnimationOptions(m_animationOptions); | ||||
m_chart->setBackgroundBrush(*m_backgroundBrush); | ||||
m_chart->setBackgroundPen(*m_backgroundPen); | ||||
m_chart->setPlotAreaBackgroundBrush(*m_plotAreaBackgroundBrush); | ||||
m_chart->setPlotAreaBackgroundPen(*m_plotAreaBackgroundPen); | ||||
} | ||||
void MainWindow::setXAxis(MainWindow::AxisMode mode) | ||||
{ | ||||
if (m_xAxis) { | ||||
m_chart->removeAxis(m_xAxis); | ||||
delete m_xAxis; | ||||
m_xAxis = 0; | ||||
} | ||||
m_xAxisMode = mode; | ||||
switch (m_xAxisMode) { | ||||
case AxisModeNone: | ||||
return; | ||||
case AxisModeValue: | ||||
m_xAxis = new QValueAxis(); | ||||
break; | ||||
case AxisModeLogValue: | ||||
m_xAxis = new QLogValueAxis(); | ||||
break; | ||||
case AxisModeDateTime: | ||||
m_xAxis = new QDateTimeAxis(); | ||||
break; | ||||
case AxisModeCategory: | ||||
m_xAxis = new QCategoryAxis(); | ||||
applyCategories(); | ||||
break; | ||||
default: | ||||
qWarning() << "Unsupported AxisMode"; | ||||
return; | ||||
} | ||||
m_chart->addAxis(m_xAxis, Qt::AlignBottom); | ||||
foreach (QAbstractSeries *series, m_seriesList) | ||||
series->attachAxis(m_xAxis); | ||||
applyRanges(); | ||||
} | ||||
void MainWindow::setYAxis(MainWindow::AxisMode mode) | ||||
{ | ||||
if (m_yAxis) { | ||||
m_chart->removeAxis(m_yAxis); | ||||
delete m_yAxis; | ||||
m_yAxis = 0; | ||||
} | ||||
m_yAxisMode = mode; | ||||
switch (m_yAxisMode) { | ||||
case AxisModeNone: | ||||
return; | ||||
case AxisModeValue: | ||||
m_yAxis = new QValueAxis(); | ||||
break; | ||||
case AxisModeLogValue: | ||||
m_yAxis = new QLogValueAxis(); | ||||
break; | ||||
case AxisModeDateTime: | ||||
m_yAxis = new QDateTimeAxis(); | ||||
break; | ||||
case AxisModeCategory: | ||||
m_yAxis = new QCategoryAxis(); | ||||
applyCategories(); | ||||
break; | ||||
default: | ||||
qWarning() << "Unsupported AxisMode"; | ||||
return; | ||||
} | ||||
m_chart->addAxis(m_yAxis, Qt::AlignLeft); | ||||
foreach (QAbstractSeries *series, m_seriesList) | ||||
series->attachAxis(m_yAxis); | ||||
applyRanges(); | ||||
} | ||||
void MainWindow::applyRanges() | ||||
{ | ||||
if (m_xAxis) { | ||||
if (m_xAxisMode == AxisModeLogValue) { | ||||
if (m_xMin <= 0) | ||||
m_xMin = 1.0; | ||||
if (m_xMax <= m_xMin) | ||||
m_xMax = m_xMin + 1.0; | ||||
} | ||||
if (m_xAxisMode == AxisModeDateTime) { | ||||
QDateTime dateTimeMin; | ||||
QDateTime dateTimeMax; | ||||
dateTimeMin.setMSecsSinceEpoch(qint64(m_xMin)); | ||||
dateTimeMax.setMSecsSinceEpoch(qint64(m_xMax)); | ||||
m_xAxis->setRange(dateTimeMin, dateTimeMax); | ||||
} else { | ||||
m_xAxis->setRange(m_xMin, m_xMax); | ||||
} | ||||
ui->xMinSpin->setValue(m_xMin); | ||||
ui->xMaxSpin->setValue(m_xMax); | ||||
} | ||||
if (m_yAxis) { | ||||
if (m_yAxisMode == AxisModeLogValue) { | ||||
if (m_yMin <= 0) | ||||
m_yMin = 1.0; | ||||
if (m_yMax <= m_yMin) | ||||
m_yMax = m_yMin + 1.0; | ||||
} | ||||
if (m_yAxisMode == AxisModeDateTime) { | ||||
QDateTime dateTimeMin; | ||||
QDateTime dateTimeMax; | ||||
dateTimeMin.setMSecsSinceEpoch(qint64(m_yMin)); | ||||
dateTimeMax.setMSecsSinceEpoch(qint64(m_yMax)); | ||||
m_yAxis->setRange(dateTimeMin, dateTimeMax); | ||||
} else { | ||||
m_yAxis->setRange(m_yMin, m_yMax); | ||||
} | ||||
ui->yMinSpin->setValue(m_yMin); | ||||
ui->yMaxSpin->setValue(m_yMax); | ||||
} | ||||
} | ||||
void MainWindow::xMinChanged(double value) | ||||
{ | ||||
m_xMin = value; | ||||
applyRanges(); | ||||
} | ||||
void MainWindow::xMaxChanged(double value) | ||||
{ | ||||
m_xMax = value; | ||||
applyRanges(); | ||||
} | ||||
void MainWindow::yMinChanged(double value) | ||||
{ | ||||
m_yMin = value; | ||||
applyRanges(); | ||||
} | ||||
void MainWindow::yMaxChanged(double value) | ||||
{ | ||||
m_yMax = value; | ||||
applyRanges(); | ||||
} | ||||
void MainWindow::animationIndexChanged(int index) | ||||
{ | ||||
switch (index) { | ||||
case 0: | ||||
m_animationOptions = QChart::NoAnimation; | ||||
break; | ||||
case 1: | ||||
m_animationOptions = QChart::SeriesAnimations; | ||||
break; | ||||
case 2: | ||||
m_animationOptions = QChart::GridAxisAnimations; | ||||
break; | ||||
case 3: | ||||
m_animationOptions = QChart::AllAnimations; | ||||
break; | ||||
default: | ||||
break; | ||||
} | ||||
m_chart->setAnimationOptions(m_animationOptions); | ||||
} | ||||
void MainWindow::xRangeChanged(qreal min, qreal max) | ||||
{ | ||||
if (!qFuzzyCompare(qreal(ui->xMinSpin->value()), min)) | ||||
ui->xMinSpin->setValue(min); | ||||
if (!qFuzzyCompare(qreal(ui->xMaxSpin->value()), max)) | ||||
ui->xMaxSpin->setValue(max); | ||||
} | ||||
void MainWindow::yRangeChanged(qreal min, qreal max) | ||||
{ | ||||
if (!qFuzzyCompare(qreal(ui->yMinSpin->value()), min)) | ||||
ui->yMinSpin->setValue(min); | ||||
if (!qFuzzyCompare(qreal(ui->yMaxSpin->value()), max)) | ||||
ui->yMaxSpin->setValue(max); | ||||
} | ||||
void MainWindow::xAxisIndexChanged(int index) | ||||
{ | ||||
switch (index) { | ||||
case 0: | ||||
setXAxis(AxisModeNone); | ||||
break; | ||||
case 1: | ||||
setXAxis(AxisModeValue); | ||||
break; | ||||
case 2: | ||||
setXAxis(AxisModeLogValue); | ||||
break; | ||||
case 3: | ||||
setXAxis(AxisModeDateTime); | ||||
break; | ||||
case 4: | ||||
setXAxis(AxisModeCategory); | ||||
break; | ||||
default: | ||||
qWarning("Invalid Index!"); | ||||
} | ||||
} | ||||
void MainWindow::yAxisIndexChanged(int index) | ||||
{ | ||||
switch (index) { | ||||
case 0: | ||||
setYAxis(AxisModeNone); | ||||
break; | ||||
case 1: | ||||
setYAxis(AxisModeValue); | ||||
break; | ||||
case 2: | ||||
setYAxis(AxisModeLogValue); | ||||
break; | ||||
case 3: | ||||
setYAxis(AxisModeDateTime); | ||||
break; | ||||
case 4: | ||||
setYAxis(AxisModeCategory); | ||||
break; | ||||
default: | ||||
qWarning("Invalid Index!"); | ||||
} | ||||
} | ||||
void MainWindow::themeIndexChanged(int index) | ||||
{ | ||||
m_chart->setTheme(QChart::ChartTheme(index)); | ||||
} | ||||
void MainWindow::addSeriesClicked() | ||||
{ | ||||
addSeries(false); | ||||
} | ||||
void MainWindow::removeSeriesClicked() | ||||
{ | ||||
if (m_seriesList.size()) { | ||||
QXYSeries *series = m_seriesList.takeAt(m_seriesList.size() - 1); | ||||
m_chart->removeSeries(series); | ||||
delete series; | ||||
} | ||||
} | ||||
void MainWindow::addGLSeriesClicked() | ||||
{ | ||||
addSeries(true); | ||||
} | ||||
void MainWindow::countIndexChanged(int index) | ||||
{ | ||||
m_pointCount = ui->countComboBox->itemText(index).toInt(); | ||||
for (int i = 0; i < m_seriesList.size(); i++) { | ||||
m_dataSource.generateData(i, 2, m_pointCount); | ||||
} | ||||
} | ||||
void MainWindow::colorIndexChanged(int index) | ||||
{ | ||||
QColor color = QColor(ui->colorsComboBox->itemText(index).toLower()); | ||||
foreach (QXYSeries *series, m_seriesList) { | ||||
if (series->type() == QAbstractSeries::SeriesTypeScatter) { | ||||
QScatterSeries *scatterSeries = static_cast<QScatterSeries *>(series); | ||||
scatterSeries->setBorderColor(color); | ||||
scatterSeries->setColor(color); | ||||
} else { | ||||
series->setColor(color); | ||||
} | ||||
} | ||||
} | ||||
void MainWindow::widthIndexChanged(int index) | ||||
{ | ||||
int width = ui->widthComboBox->itemText(index).toInt(); | ||||
foreach (QXYSeries *series, m_seriesList) { | ||||
if (series->type() == QAbstractSeries::SeriesTypeScatter) { | ||||
QScatterSeries *scatterSeries = static_cast<QScatterSeries *>(series); | ||||
scatterSeries->setMarkerSize(width); | ||||
} else { | ||||
QColor color = QColor(ui->colorsComboBox->itemText( | ||||
ui->colorsComboBox->currentIndex()).toLower()); | ||||
series->setPen(QPen(QBrush(color), width)); | ||||
} | ||||
} | ||||
} | ||||
void MainWindow::backgroundIndexChanged(int index) | ||||
{ | ||||
delete m_backgroundBrush; | ||||
delete m_backgroundPen; | ||||
switch (index) { | ||||
case 0: | ||||
m_backgroundBrush = new QBrush(Qt::white); | ||||
m_backgroundPen = new QPen(Qt::NoPen); | ||||
break; | ||||
case 1: | ||||
m_backgroundBrush = new QBrush(Qt::blue); | ||||
m_backgroundPen = new QPen(Qt::NoPen); | ||||
break; | ||||
case 2: | ||||
m_backgroundBrush = new QBrush(Qt::yellow); | ||||
m_backgroundPen = new QPen(Qt::black, 2); | ||||
break; | ||||
default: | ||||
break; | ||||
} | ||||
m_chart->setBackgroundBrush(*m_backgroundBrush); | ||||
m_chart->setBackgroundPen(*m_backgroundPen); | ||||
} | ||||
void MainWindow::plotAreaIndexChanged(int index) | ||||
{ | ||||
delete m_plotAreaBackgroundBrush; | ||||
delete m_plotAreaBackgroundPen; | ||||
switch (index) { | ||||
case 0: | ||||
m_plotAreaBackgroundBrush = new QBrush(Qt::green); | ||||
m_plotAreaBackgroundPen = new QPen(Qt::green); | ||||
m_chart->setPlotAreaBackgroundVisible(false); | ||||
break; | ||||
case 1: | ||||
m_plotAreaBackgroundBrush = new QBrush(Qt::magenta); | ||||
m_plotAreaBackgroundPen = new QPen(Qt::NoPen); | ||||
m_chart->setPlotAreaBackgroundVisible(true); | ||||
break; | ||||
case 2: | ||||
m_plotAreaBackgroundBrush = new QBrush(Qt::lightGray); | ||||
m_plotAreaBackgroundPen = new QPen(Qt::red, 6); | ||||
m_chart->setPlotAreaBackgroundVisible(true); | ||||
break; | ||||
default: | ||||
break; | ||||
} | ||||
m_chart->setPlotAreaBackgroundBrush(*m_plotAreaBackgroundBrush); | ||||
m_chart->setPlotAreaBackgroundPen(*m_plotAreaBackgroundPen); | ||||
} | ||||
void MainWindow::applyCategories() | ||||
{ | ||||
// Basic layout is three categories, extended has five | ||||
if (m_xAxisMode == AxisModeCategory) { | ||||
QCategoryAxis *angCatAxis = static_cast<QCategoryAxis *>(m_xAxis); | ||||
if (angCatAxis->count() == 0) { | ||||
angCatAxis->setStartValue(2); | ||||
angCatAxis->append("Category A", 6); | ||||
angCatAxis->append("Category B", 12); | ||||
angCatAxis->append("Category C", 18); | ||||
} | ||||
} | ||||
if (m_yAxisMode == AxisModeCategory) { | ||||
QCategoryAxis *radCatAxis = static_cast<QCategoryAxis *>(m_yAxis); | ||||
if (radCatAxis->count() == 0) { | ||||
radCatAxis->setStartValue(1); | ||||
radCatAxis->append("Category 1", 3); | ||||
radCatAxis->append("Category 2", 4); | ||||
radCatAxis->append("Category 3", 8); | ||||
} | ||||
} | ||||
} | ||||
void MainWindow::addSeries(bool gl) | ||||
{ | ||||
QColor color = QColor(ui->colorsComboBox->itemText(ui->colorsComboBox->currentIndex()).toLower()); | ||||
int width = ui->widthComboBox->itemText(ui->widthComboBox->currentIndex()).toInt(); | ||||
if (m_seriesList.size() < maxSeriesCount) { | ||||
QXYSeries *series; | ||||
if (qrand() % 2) { | ||||
series = new QLineSeries; | ||||
series->setPen(QPen(QBrush(color), width)); | ||||
} else { | ||||
QScatterSeries *scatterSeries = new QScatterSeries; | ||||
scatterSeries->setMarkerSize(width); | ||||
scatterSeries->setBorderColor(color); | ||||
scatterSeries->setBrush(QBrush(color)); | ||||
series = scatterSeries; | ||||
} | ||||
series->setUseOpenGL(gl); | ||||
m_dataSource.generateData(m_seriesList.size(), 2, m_pointCount); | ||||
m_seriesList.append(series); | ||||
m_chart->addSeries(series); | ||||
if (m_xAxis) | ||||
series->attachAxis(m_xAxis); | ||||
if (m_yAxis) | ||||
series->attachAxis(m_yAxis); | ||||
applyRanges(); | ||||
} | ||||
} | ||||