##// END OF EJS Templates
Fix mouse event interception by scatter chart....
Fix mouse event interception by scatter chart. The scatter chart itself shouldn't be selectable. The scatter chart occupies the entire plot area of the chart, and therefore blocks mouse events from all items below it. Only the individual scatter markers need to be selectable. Change-Id: I664c16ced24e3fc4c068b850c8c612e2d797ee4b Reviewed-by: Titta Heikkala <titta.heikkala@theqtcompany.com>

File last commit:

r2740:377e4516d036
r2747:31ef05db7ba9
Show More
mainwidget.cpp
517 lines | 16.5 KiB | text/x-c | CppLexer
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc
** All rights reserved.
** For any questions to Digia, please use contact form at http://qt.io
**
** This file is part of the Qt Charts module.
**
** Licensees holding valid commercial license for Qt may use this file in
** accordance with the Qt License Agreement provided with the Software
** or, alternatively, in accordance with the terms contained in a written
** agreement between you and Digia.
**
** If you have questions regarding the use of this file, please use
** contact form at http://qt.io
**
****************************************************************************/
#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));
}