/****************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Charts module. ** ** $QT_BEGIN_LICENSE:COMM$ ** ** 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 http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** $QT_END_LICENSE$ ** ******************************************************************************/ #include "mainwidget.h" #include "customtablemodel.h" #include "pentool.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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 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 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 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)); }