##// END OF EJS Templates
improvements in execution time, colorbar ok, more work to do on axes,
improvements in execution time, colorbar ok, more work to do on axes,

File last commit:

r0:5db0360e1259 default
r3:ab1c9ba54a31 default
Show More
mainwidget.cpp
528 lines | 17.1 KiB | text/x-c | CppLexer
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Charts module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL$
** 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
** 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.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "mainwidget.h"
#include "customtablemodel.h"
#include "pentool.h"
#include <QtCharts/QVBoxPlotModelMapper>
#include <QtWidgets/QTableView>
#include <QtWidgets/QHeaderView>
#include <QtCharts/QChartView>
#include <QtCharts/QBoxPlotSeries>
#include <QtCharts/QBoxSet>
#include <QtCharts/QLegend>
#include <QtCharts/QBarCategoryAxis>
#include <QtGui/QBrush>
#include <QtGui/QColor>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QSpinBox>
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QLabel>
#include <QtWidgets/QSpacerItem>
#include <QtWidgets/QMessageBox>
#include <cmath>
#include <QtCore/QDebug>
#include <QtGui/QStandardItemModel>
#include <QtCharts/QBarCategoryAxis>
#include <QtCharts/QLogValueAxis>
QT_CHARTS_USE_NAMESPACE
static const QString allCategories[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
static const int maxCategories = 12;
MainWidget::MainWidget(QWidget *parent) :
QWidget(parent),
m_chart(0),
m_axis(0),
m_rowPos(0),
m_seriesCount(0)
{
m_chart = new QChart();
m_penTool = new PenTool("Whiskers pen", this);
// Grid layout for the controls for configuring the chart widget
QGridLayout *grid = new QGridLayout();
// Create add a series button
QPushButton *addSeriesButton = new QPushButton("Add a series");
connect(addSeriesButton, SIGNAL(clicked()), this, SLOT(addSeries()));
grid->addWidget(addSeriesButton, m_rowPos++, 1);
// Create remove a series button
QPushButton *removeSeriesButton = new QPushButton("Remove a series");
connect(removeSeriesButton, SIGNAL(clicked()), this, SLOT(removeSeries()));
grid->addWidget(removeSeriesButton, m_rowPos++, 1);
// Create add a single box button
QPushButton *addBoxButton = new QPushButton("Add a box");
connect(addBoxButton, SIGNAL(clicked()), this, SLOT(addBox()));
grid->addWidget(addBoxButton, m_rowPos++, 1);
// Create insert a box button
QPushButton *insertBoxButton = new QPushButton("Insert a box");
connect(insertBoxButton, SIGNAL(clicked()), this, SLOT(insertBox()));
grid->addWidget(insertBoxButton, m_rowPos++, 1);
// Create add a single box button
QPushButton *removeBoxButton = new QPushButton("Remove a box");
connect(removeBoxButton, SIGNAL(clicked()), this, SLOT(removeBox()));
grid->addWidget(removeBoxButton, m_rowPos++, 1);
// Create clear button
QPushButton *clearButton = new QPushButton("Clear");
connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));
grid->addWidget(clearButton, m_rowPos++, 1);
// Create clear button
QPushButton *clearBoxButton = new QPushButton("ClearBox");
connect(clearBoxButton, SIGNAL(clicked()), this, SLOT(clearBox()));
grid->addWidget(clearBoxButton, m_rowPos++, 1);
// Create set brush button
QPushButton *setBrushButton = new QPushButton("Set brush");
connect(setBrushButton, SIGNAL(clicked()), this, SLOT(setBrush()));
grid->addWidget(setBrushButton, m_rowPos++, 1);
// Create set whiskers pen button
QPushButton *setWhiskersButton = new QPushButton("Whiskers pen");
connect(setWhiskersButton, SIGNAL(clicked()), m_penTool, SLOT(show()));
connect(m_penTool, SIGNAL(changed()), this, SLOT(changePen()));
grid->addWidget(setWhiskersButton, m_rowPos++, 1);
// Box width setting
m_boxWidthSB = new QDoubleSpinBox();
m_boxWidthSB->setMinimum(-1.0);
m_boxWidthSB->setMaximum(2.0);
m_boxWidthSB->setSingleStep(0.1);
m_boxWidthSB->setValue(0.5);
grid->addWidget(new QLabel("Box width:"), m_rowPos, 0);
grid->addWidget(m_boxWidthSB, m_rowPos++, 1);
connect(m_boxWidthSB, SIGNAL(valueChanged(double)), this, SLOT(setBoxWidth(double)));
initThemeCombo(grid);
initCheckboxes(grid);
QTableView *tableView = new QTableView;
m_model = new CustomTableModel(tableView);
tableView->setModel(m_model);
tableView->setMaximumWidth(200);
grid->addWidget(tableView, m_rowPos++, 0, 3, 2, Qt::AlignLeft);
tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
tableView->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
// add row with empty label to make all the other rows static
grid->addWidget(new QLabel(""), grid->rowCount(), 0);
grid->setRowStretch(grid->rowCount() - 1, 1);
// Create chart view with the chart
m_chartView = new QChartView(m_chart, this);
// As a default antialiasing is off
m_chartView->setRenderHint(QPainter::Antialiasing, false);
// Another grid layout as a main layout
QGridLayout *mainLayout = new QGridLayout();
mainLayout->addLayout(grid, 0, 0);
mainLayout->addWidget(m_chartView, 0, 1, 3, 1);
setLayout(mainLayout);
legendToggled(false);
animationToggled(false);
}
// Combo box for selecting theme
void MainWidget::initThemeCombo(QGridLayout *grid)
{
QComboBox *chartTheme = new QComboBox();
chartTheme->addItem("Default");
chartTheme->addItem("Light");
chartTheme->addItem("Blue Cerulean");
chartTheme->addItem("Dark");
chartTheme->addItem("Brown Sand");
chartTheme->addItem("Blue NCS");
chartTheme->addItem("High Contrast");
chartTheme->addItem("Blue Icy");
chartTheme->addItem("Qt");
connect(chartTheme, SIGNAL(currentIndexChanged(int)),
this, SLOT(changeChartTheme(int)));
grid->addWidget(new QLabel("Chart theme:"), m_rowPos, 0);
grid->addWidget(chartTheme, m_rowPos++, 1);
}
// Different check boxes for customizing chart
void MainWidget::initCheckboxes(QGridLayout *grid)
{
QCheckBox *animationCheckBox = new QCheckBox("Animation");
connect(animationCheckBox, SIGNAL(toggled(bool)), this, SLOT(animationToggled(bool)));
animationCheckBox->setChecked(false);
grid->addWidget(animationCheckBox, m_rowPos++, 0);
QCheckBox *legendCheckBox = new QCheckBox("Legend");
connect(legendCheckBox, SIGNAL(toggled(bool)), this, SLOT(legendToggled(bool)));
legendCheckBox->setChecked(false);
grid->addWidget(legendCheckBox, m_rowPos++, 0);
QCheckBox *titleCheckBox = new QCheckBox("Title");
connect(titleCheckBox, SIGNAL(toggled(bool)), this, SLOT(titleToggled(bool)));
titleCheckBox->setChecked(false);
grid->addWidget(titleCheckBox, m_rowPos++, 0);
QCheckBox *antialiasingCheckBox = new QCheckBox("Antialiasing");
connect(antialiasingCheckBox, SIGNAL(toggled(bool)), this, SLOT(antialiasingToggled(bool)));
antialiasingCheckBox->setChecked(false);
grid->addWidget(antialiasingCheckBox, m_rowPos++, 0);
QCheckBox *modelMapperCheckBox = new QCheckBox("Use model mapper");
connect(modelMapperCheckBox, SIGNAL(toggled(bool)), this, SLOT(modelMapperToggled(bool)));
modelMapperCheckBox->setChecked(false);
grid->addWidget(modelMapperCheckBox, m_rowPos++, 0);
m_boxOutlined = new QCheckBox("Box outlined");
connect(m_boxOutlined, SIGNAL(toggled(bool)), this, SLOT(boxOutlineToggled(bool)));
m_boxOutlined->setChecked(true);
grid->addWidget(m_boxOutlined, m_rowPos++, 0);
}
void MainWidget::updateAxis(int categoryCount)
{
if (!m_axis) {
m_chart->createDefaultAxes();
m_axis = new QBarCategoryAxis();
}
QStringList categories;
for (int i = 0; i < categoryCount; i++)
categories << allCategories[i];
m_axis->setCategories(categories);
}
void MainWidget::addSeries()
{
qDebug() << "BoxPlotTester::MainWidget::addSeries()";
if (m_seriesCount > 9)
return;
// Initial data
QBoxSet *set0 = new QBoxSet();
QBoxSet *set1 = new QBoxSet();
QBoxSet *set2 = new QBoxSet();
QBoxSet *set3 = new QBoxSet();
QBoxSet *set4 = new QBoxSet();
QBoxSet *set5 = new QBoxSet();
// low bot med top upp
*set0 << -1 << 2 << 4 << 13 << 15;
*set1 << 5 << 6 << 7.5 << 8 << 12;
*set2 << 3 << 5 << 5.7 << 8 << 9;
*set3 << 5 << 6 << 6.8 << 7 << 8;
*set4 << 4 << 5 << 5.2 << 6 << 7;
*set5 << 4 << 7 << 8.2 << 9 << 10;
m_series[m_seriesCount] = new QBoxPlotSeries();
m_series[m_seriesCount]->append(set0);
m_series[m_seriesCount]->append(set1);
m_series[m_seriesCount]->append(set2);
m_series[m_seriesCount]->append(set3);
m_series[m_seriesCount]->append(set4);
m_series[m_seriesCount]->append(set5);
m_series[m_seriesCount]->setName("Box & Whiskers");
connect(m_series[m_seriesCount], SIGNAL(clicked(QBoxSet*)), this, SLOT(boxClicked(QBoxSet*)));
connect(m_series[m_seriesCount], SIGNAL(pressed(QBoxSet*)), this, SLOT(boxPressed(QBoxSet*)));
connect(m_series[m_seriesCount], SIGNAL(released(QBoxSet*)), this, SLOT(boxReleased(QBoxSet*)));
connect(m_series[m_seriesCount], SIGNAL(doubleClicked(QBoxSet*)),
this, SLOT(boxDoubleClicked(QBoxSet*)));
connect(m_series[m_seriesCount], SIGNAL(hovered(bool, QBoxSet*)), this, SLOT(boxHovered(bool, QBoxSet*)));
connect(set1, SIGNAL(clicked()), this, SLOT(singleBoxClicked()));
connect(set1, SIGNAL(pressed()), this, SLOT(singleBoxPressed()));
connect(set1, SIGNAL(released()), this, SLOT(singleBoxReleased()));
connect(set1, SIGNAL(doubleClicked()), this, SLOT(singleBoxDoubleClicked()));
connect(set2, SIGNAL(hovered(bool)), this, SLOT(singleBoxHovered(bool)));
m_series[m_seriesCount]->setBoxOutlineVisible(m_boxOutlined->checkState());
m_series[m_seriesCount]->setBoxWidth(m_boxWidthSB->value());
m_chart->addSeries(m_series[m_seriesCount]);
updateAxis(m_series[0]->count());
m_chart->setAxisX(m_axis, m_series[m_seriesCount]);
m_seriesCount++;
}
void MainWidget::removeSeries()
{
qDebug() << "BoxPlotTester::MainWidget::removeSeries()";
if (m_seriesCount > 0) {
m_seriesCount--;
m_chart->removeSeries(m_series[m_seriesCount]);
delete m_series[m_seriesCount];
m_series[m_seriesCount] = 0;
} else {
qDebug() << "Create a series first";
}
}
void MainWidget::addBox()
{
qDebug() << "BoxPlotTester::MainWidget::addBox()";
if (m_seriesCount > 0 && m_series[0]->count() < maxCategories) {
QBoxSet *newSet = new QBoxSet();
newSet->setValue(QBoxSet::LowerExtreme, 5.0);
newSet->setValue(QBoxSet::LowerQuartile, 6.0);
newSet->setValue(QBoxSet::Median, 6.8);
newSet->setValue(QBoxSet::UpperQuartile, 7.0);
newSet->setValue(QBoxSet::UpperExtreme, 8.0);
updateAxis(m_series[0]->count() + 1);
m_series[0]->append(newSet);
}
}
void MainWidget::insertBox()
{
qDebug() << "BoxPlotTester::MainWidget::insertBox()";
if (m_seriesCount > 0 && m_series[0]->count() < maxCategories) {
updateAxis(m_series[0]->count() + 1);
for (int i = 0; i < m_seriesCount; i++) {
QBoxSet *newSet = new QBoxSet();
*newSet << 2 << 6 << 6.8 << 7 << 10;
m_series[i]->insert(1, newSet);
}
}
}
void MainWidget::removeBox()
{
qDebug() << "BoxPlotTester::MainWidget::removeBox";
if (m_seriesCount > 0) {
for (int i = 0; i < m_seriesCount; i++) {
qDebug() << "m_series[i]->count() = " << m_series[i]->count();
if (m_series[i]->count()) {
QList<QBoxSet *> sets = m_series[i]->boxSets();
m_series[i]->remove(sets.at(m_series[i]->count() - 1));
}
}
updateAxis(m_series[0]->count());
} else {
qDebug() << "Create a series first";
}
}
void MainWidget::clear()
{
qDebug() << "BoxPlotTester::MainWidget::clear";
if (m_seriesCount > 0)
m_series[0]->clear();
else
qDebug() << "Create a series first";
}
void MainWidget::clearBox()
{
qDebug() << "BoxPlotTester::MainWidget::clearBox";
if (m_seriesCount > 0) {
QList<QBoxSet *> sets = m_series[0]->boxSets();
if (sets.count() > 1)
sets.at(1)->clear();
else
qDebug() << "Create a series with at least two items first";
} else {
qDebug() << "Create a series first";
}
}
void MainWidget::setBrush()
{
qDebug() << "BoxPlotTester::MainWidget::setBrush";
if (m_seriesCount > 0) {
QList<QBoxSet *> sets = m_series[0]->boxSets();
if (sets.count() > 1)
sets.at(1)->setBrush(QBrush(QColor(Qt::yellow)));
else
qDebug() << "Create a series with at least two items first";
} else {
qDebug() << "Create a series first";
}
}
void MainWidget::animationToggled(bool enabled)
{
qDebug() << "BoxPlotTester::Animation toggled to " << enabled;
if (enabled)
m_chart->setAnimationOptions(QChart::SeriesAnimations);
else
m_chart->setAnimationOptions(QChart::NoAnimation);
}
void MainWidget::legendToggled(bool enabled)
{
qDebug() << "BoxPlotTester::Legend toggled to " << enabled;
m_chart->legend()->setVisible(enabled);
if (enabled)
m_chart->legend()->setAlignment(Qt::AlignBottom);
}
void MainWidget::titleToggled(bool enabled)
{
qDebug() << "BoxPlotTester::Title toggled to " << enabled;
if (enabled)
m_chart->setTitle("Simple boxplotchart example");
else
m_chart->setTitle("");
}
void MainWidget::antialiasingToggled(bool enabled)
{
qDebug() << "BoxPlotTester::antialiasingToggled toggled to " << enabled;
m_chartView->setRenderHint(QPainter::Antialiasing, enabled);
}
void MainWidget::boxOutlineToggled(bool visible)
{
qDebug() << "BoxPlotTester::boxOutlineToggled toggled to " << visible;
for (int i = 0; i < m_seriesCount; i++)
m_series[i]->setBoxOutlineVisible(visible);
}
void MainWidget::modelMapperToggled(bool enabled)
{
if (enabled) {
m_series[m_seriesCount] = new QBoxPlotSeries();
int first = 0;
int count = 5;
QVBoxPlotModelMapper *mapper = new QVBoxPlotModelMapper(this);
mapper->setFirstBoxSetColumn(0);
mapper->setLastBoxSetColumn(5);
mapper->setFirstRow(first);
mapper->setRowCount(count);
mapper->setSeries(m_series[m_seriesCount]);
mapper->setModel(m_model);
m_chart->addSeries(m_series[m_seriesCount]);
m_seriesCount++;
} else {
removeSeries();
}
}
void MainWidget::changeChartTheme(int themeIndex)
{
qDebug() << "BoxPlotTester::changeChartTheme: " << themeIndex;
if (themeIndex == 0)
m_chart->setTheme(QChart::ChartThemeLight);
else
m_chart->setTheme((QChart::ChartTheme) (themeIndex - 1));
}
void MainWidget::boxClicked(QBoxSet *set)
{
qDebug() << "boxClicked, median = " << set->at(QBoxSet::Median);
}
void MainWidget::boxHovered(bool state, QBoxSet *set)
{
if (state)
qDebug() << "box median " << set->at(QBoxSet::Median) << " hover started";
else
qDebug() << "box median " << set->at(QBoxSet::Median) << " hover ended";
}
void MainWidget::boxPressed(QBoxSet *set)
{
qDebug() << "boxPressed, median = " << set->at(QBoxSet::Median);
}
void MainWidget::boxReleased(QBoxSet *set)
{
qDebug() << "boxReleased, median = " << set->at(QBoxSet::Median);
}
void MainWidget::boxDoubleClicked(QBoxSet *set)
{
qDebug() << "boxDoubleClicked, median = " << set->at(QBoxSet::Median);
}
void MainWidget::singleBoxClicked()
{
qDebug() << "singleBoxClicked";
}
void MainWidget::singleBoxPressed()
{
qDebug() << "singleBoxPressed";
}
void MainWidget::singleBoxReleased()
{
qDebug() << "singleBoxReleased";
}
void MainWidget::singleBoxDoubleClicked()
{
qDebug() << "singleBoxDoubleClicked";
}
void MainWidget::singleBoxHovered(bool state)
{
if (state)
qDebug() << "single box hover started";
else
qDebug() << "single box hover ended";
}
void MainWidget::changePen()
{
qDebug() << "changePen() = " << m_penTool->pen();
for (int i = 0; i < m_seriesCount; i++)
m_series[i]->setPen(m_penTool->pen());
}
void MainWidget::setBoxWidth(double width)
{
qDebug() << "setBoxWidth to " << width;
for (int i = 0; i < m_seriesCount; i++)
m_series[i]->setBoxWidth(qreal(width));
}