AdvancedFeaturesDemo Example
#include "mainwindow.h"
#include <QApplication>
#include <QGroupBox>
#include <QComboBox>
#include <QCheckBox>
#include <QMessageBox>
#include <QPainter>
#include <QFormLayout>
#include <QDateTime>
#include <qmath.h>
class AdvancedChart : public Qtitan::Chart
{
public:
AdvancedChart(QWidget* parent = 0);
protected:
virtual void paintEvent(QPaintEvent* event);
virtual void resizeEvent(QResizeEvent* event);
public:
qreal m_XLine;
QVector<QPointF> m_arMarkers;
};
AdvancedChart::AdvancedChart(QWidget* parent)
: Qtitan::Chart(parent)
{
}
static const QSizeF m_szMarker(5.0, 5.0);
void AdvancedChart::paintEvent(QPaintEvent* event)
{
Qtitan::Chart::paintEvent(event);
QPainter p(this);
for (int i = 0; i < m_arMarkers.size(); i++)
{
ChartSeries2D* series2D = (ChartSeries2D*)series().at(i);
QColor color = series2D->color();
ChartView2D* view = static_cast<ChartView2D *>(series2D->view());
ChartAxis* axisY = view->axisY();
Q_ASSERT(axisY != Q_NULL);
QRect rectAxisBounds = axisY->boundingRect();
rectAxisBounds.setWidth(view->boundingRect().width());
QPointF ptMarker = m_arMarkers[i];
if (rectAxisBounds.contains(ptMarker.toPoint()))
{
QPainter::RenderHints hints = p.renderHints();
p.setRenderHints(hints, false);
p.setRenderHint(QPainter::Antialiasing);
const QPen savePen = p.pen();
p.setPen(QPen(color.darker()));
QBrush saveBrush = p.brush();
color.setAlpha(140);
p.setBrush(color);
p.drawEllipse(ptMarker, m_szMarker.width(), m_szMarker.height());
p.setBrush(saveBrush);
p.setPen(savePen);
p.setRenderHints(p.renderHints(), false);
p.setRenderHints(hints, true);
}
}
if (m_XLine != -1.0)
{
const QPen savePen = p.pen();
p.setPen(QPen(QBrush(QColor(Qt::red)), 1.0, Qt::DashLine));
QRect rect = viewRect();
p.drawLine(m_XLine, rect.top(), m_XLine, rect.bottom());
p.setPen(savePen);
}
}
void AdvancedChart::resizeEvent(QResizeEvent* event)
{
Qtitan::Chart::resizeEvent(event);
m_arMarkers.clear();
m_XLine = -1.;
}
#define DEFAULT_INFO tr("Move the mouse cursor over the chart and see information on hovered chart component")
MainWindow::MainWindow()
: DemoChartWindow(tr("Advanced Features"))
{
setChart(new AdvancedChart());
createSeriesParametrs();
seriesChanged(m_seriesSwitcher->currentIndex());
connect(m_chart, SIGNAL(chartMouseTrack(ChartHitInfo*)), this, SLOT(mouseTrack(ChartHitInfo*)), Qt::DirectConnection);
connect(m_chart, SIGNAL(chartMouseUp(ChartHitInfo*)), this, SLOT(mouseUp(ChartHitInfo*)), Qt::DirectConnection);
}
void MainWindow::createSeriesParametrs()
{
QGroupBox* seriesTypeGroup = createGroupParameters(tr("Series"));
QFormLayout* localLayout = (QFormLayout*)seriesTypeGroup->layout();
m_seriesSwitcher = new QComboBox(seriesTypeGroup);
m_seriesSwitcher->addItem(tr("Combined"), QVariant(Combined));
m_seriesSwitcher->addItem(tr("Secondary Axis"), QVariant(SecondaryAxis));
m_seriesSwitcher->addItem(tr("Interactive"), QVariant(Interactive));
connect(m_seriesSwitcher, SIGNAL(currentIndexChanged(int)), this, SLOT(seriesChanged(int)));
m_showSecondaryAxisX = new QCheckBox(tr("Secondary X Axis"), seriesTypeGroup);
m_showSecondaryAxisX->setCheckState(Qt::Checked);
m_showSecondaryAxisX->setVisible(false);
connect(m_showSecondaryAxisX, SIGNAL(stateChanged(int)), this, SLOT(showSecondaryAxisXChanged(int)));
m_showSecondaryAxisY = new QCheckBox(tr("Secondary Y Axis"), seriesTypeGroup);
m_showSecondaryAxisY->setCheckState(Qt::Checked);
m_showSecondaryAxisY->setVisible(false);
connect(m_showSecondaryAxisY, SIGNAL(stateChanged(int)), this, SLOT(showSecondaryAxisYChanged(int)));
createLabelsGroup();
m_dataLabelsGroup->setVisible(false);
connect(m_angleDataLabelsSwitcher, SIGNAL(currentIndexChanged(int)), this, SLOT(updateAngleChanged(int)));
m_hitTestResult = new QLabel(DEFAULT_INFO, seriesTypeGroup);
m_hitTestResult->setWordWrap(true);
m_hitTestResult->setVisible(false);
m_hitTestResult->setMinimumWidth(180);
m_hitTestResult->setMaximumWidth(180);
m_hitTestResult->setMinimumHeight(100);
m_hitTestResult->setMaximumHeight(100);
localLayout->addRow(m_seriesSwitcher);
localLayout->addRow(m_showSecondaryAxisX);
localLayout->addRow(m_showSecondaryAxisY);
localLayout->addRow(m_hitTestResult);
}
void MainWindow::createCombined()
{
createTitle(tr("Area, Bar and Line"));
m_chart->legend()->setVisible(true);
m_chart->legend()->setVerticalAlignment(ChartLegend::LegendCenter);
ChartAreaSeries2D* series1 = new ChartAreaSeries2D();
series1->setName(tr("Area"));
m_chart->appendSeries(series1);
ChartBarSeries2D* series2 = new ChartBarSeries2D();
series2->setTransparency(180);
series2->setName(tr("Bar"));
m_chart->appendSeries(series2);
ChartLineSeries2D* series3 = new ChartLineSeries2D();
series3->setName(tr("Line"));
m_chart->appendSeries(series3);
qreal arTemp[3][12] = {
{ 28.5, 29.5, 24.5, 29.0, 32.6, 34.5, 36.5, 28.0, 34.6, 36.0, 40.0, 39.0 },
{ 23.5, 28.0, 34.0, 32.0, 31.0, 25.0, 39.0, 40.0, 42.0, 39.0, 45.0, 50.0 },
{ 3.0, 5.0, 9.0, 13.0, 17.0, 21.0, 25.0, 29.0, 36.0, 42.0, 48.0, 54.0 }};
for (int month = 1; month <= 12; month++)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
QString strMonth = QLocale::system().monthName(month, QLocale::ShortFormat);
#else
QString strMonth = QDate::shortMonthName(month);
#endif
series1->addAxisPointY(arTemp[0][month - 1], strMonth);
series2->addAxisPointY(arTemp[1][month - 1], strMonth);
series3->addAxisPointY(arTemp[2][month - 1], strMonth);
}
}
void MainWindow::createSecondaryAxis()
{
m_chart->legend()->setVisible(true);
m_chart->legend()->setVerticalAlignment(ChartLegend::LegendCenter);
ChartSplineSeries2D* series1 = new ChartSplineSeries2D();
series1->setName(tr("Series1"));
m_chart->appendSeries(series1);
series1->setMarkerType(ChartMarker::Triangle);
series1->setMarkerSize(16);
series1->addXY(1, 0.0);
series1->addXY(2, 2.0);
series1->addXY(3, 5.0);
series1->addXY(4, 3.0);
series1->addXY(5, 3.5);
series1->addXY(6, 5.0);
series1->addXY(7, 8.0);
series1->addXY(8, 7.0);
ChartSplineSeries2D* series2 = new ChartSplineSeries2D();
series2->setName(tr("Series2"));
m_chart->appendSeries(series2);
series2->setMarkerType(ChartMarker::Star);
series2->setMarkerSize(16);
series2->addXY(1, 2.0);
series2->addXY(2, 6.0);
series2->addXY(3, 12.0);
series2->addXY(4, 16.0);
series2->addXY(5, 14.0);
series2->addXY(6, 9.0);
series2->addXY(7, 6.0);
series2->addXY(8, 2.0);
}
void MainWindow::createInteractive()
{
createTitle(tr("Weather Report"));
m_chart->setAreasOrientation(Qt::Vertical);
m_chart->legend()->setVisible(true);
m_chart->legend()->setVerticalAlignment(ChartLegend::LegendCenter);
ChartView2D* view1 = new ChartView2D();
m_chart->appendView(view1);
m_axisY1 = view1->axisY();
ChartAxisTitle* titleY = m_axisY1->title();
titleY->setText(tr("Pressure"));
titleY->setVisible(true);
view1->axisY()->setAutoRange(false);
view1->axisY()->setFixedRange(15, 25);
view1->axisX()->setVisible(false);
ChartView2D* view2 = new ChartView2D();
m_chart->appendView(view2);
titleY = view2->axisY()->title();
titleY->setText(tr("Temperature"));
titleY->setVisible(true);
view2->axisY()->setAutoRange(false);
view2->axisY()->setFixedRange(1012, 1025);
view2->axisX()->setVisible(false);
ChartView2D* view3 = new ChartView2D();
m_chart->appendView(view3);
m_axisY2 = view3->axisY();
titleY = m_axisY2->title();
titleY->setText(tr("Humidity,%"));
titleY->setVisible(true);
view3->axisX()->title()->setText(tr("Days"));
view3->axisX()->title()->setVisible(true);
ChartLineSeries2D* series1 = new ChartLineSeries2D();
series1->setName(tr("Temperature"));
series1->setMarkerVisible(false);
series1->label()->setVisible(true);
((ChartPointSeriesLabel*)series1->label())->setAngle(-270);
view1->appendSeries(series1);
ChartAreaSeries2D* series2 = new ChartAreaSeries2D();
series2->setName(tr("Pressure"));
series2->setMarkerVisible(false);
series2->label()->setVisible(false);
view2->appendSeries(series2);
ChartBarSeries2D* series3 = new ChartBarSeries2D();
series3->setName(tr("Humidity"));
series3->label()->setVisible(false);
view3->appendSeries(series3);
for (int day = 1; day <= 31; day++)
{
series1->addXY(day, (int)(20.0 + qtn_rand(-5.0, 5.0)));
series2->addXY(day, 1020.0 + qtn_rand(-4.0, 4.0));
series3->addXY(day, 50.0 + qtn_rand(-40.0, 40.0));
}
}
void MainWindow::updateValueParameters()
{
m_dataLabelsGroup->setVisible(false);
DemoChartWindow::updateValueParameters();
int indexChart = m_seriesSwitcher->currentIndex();
if (indexChart == SecondaryAxis)
{
m_showSecondaryAxisX->setVisible(true);
m_showSecondaryAxisY->setVisible(true);
if (m_showSecondaryAxisX->isVisible() && m_showSecondaryAxisY->isVisible())
{
showSecondaryAxisXChanged(m_showSecondaryAxisX->checkState());
showSecondaryAxisYChanged(m_showSecondaryAxisY->checkState());
}
}
else
{
m_showSecondaryAxisX->setVisible(false);
m_showSecondaryAxisY->setVisible(false);
}
if (indexChart == Combined)
{
m_dataLabelsGroup->setVisible(true);
showDataLabels(m_dataLabelsGroup->isChecked());
if (m_angleDataLabelsSwitcher && m_angleDataLabelsSwitcher->isVisible())
{
labelsAngleChanged(m_angleDataLabelsSwitcher->currentIndex());
const SeriesList& listSeries = m_chart->series();
for (int i = 0; i < listSeries.count(); i++)
{
if (ChartBarSeries2D* series= qobject_cast<ChartBarSeries2D*>(listSeries.at(i)))
{
ChartBarSeriesLabel* label = (ChartBarSeriesLabel*)series->label();
label->setPosition(ChartBarSeriesLabel::ChartBarLabelTop);
}
}
}
}
}
void MainWindow::seriesChanged(int index)
{
((AdvancedChart*)m_chart)->m_XLine = -1.;
((AdvancedChart*)m_chart)->m_arMarkers.clear();
m_chart->clearSeries();
m_chart->clearTitles();
m_chart->setBackgroundBrush(QBrush());
QVariant var = m_seriesSwitcher->itemData(index);
switch((SeriesType)var.toUInt())
{
case Combined :
{
m_chart->enableMouseTrackingMode(ChartHitInfo::HitNone);
m_hitTestResult->setVisible(false);
createCombined();
}
break;
case SecondaryAxis :
{
m_chart->enableMouseTrackingMode(ChartHitInfo::HitNone);
m_hitTestResult->setVisible(false);
createSecondaryAxis();
}
break;
case Interactive :
{
m_chart->enableMouseTrackingMode(ChartHitInfo::HitChartArea | ChartHitInfo::HitTitle | ChartHitInfo::HitDataPoint |
ChartHitInfo::HitLegend | ChartHitInfo::HitAxis | ChartHitInfo::HitAxisName | ChartHitInfo::HitView);
m_hitTestResult->setVisible(true);
createInteractive();
}
break;
default:
break;
}
updateValueParameters();
}
void MainWindow::showSecondaryAxisXChanged(int state)
{
ChartView2D* view2D = static_cast<ChartView2D *>(m_chart->views().at(0));
if (Qt::Checked != state)
view2D->secondaryAxisX()->setVisible(false);
else
showAxisXChanged(Qt::Checked);
ChartAxisTitle* titleX = view2D->axisX()->title();
Q_ASSERT(titleX != Q_NULL);
if (Qt::Checked == state)
{
view2D->secondaryAxisX()->title()->setText(tr("Series 2 X"));
view2D->secondaryAxisX()->title()->setVisible(true);
titleX->setText(tr("Series 1 X"));
titleX->setVisible(true);
}
else
{
titleX->setText(tr("Series 1 and 2 X"));
titleX->setVisible(true);
}
ChartSeries2D* impl = (ChartSeries2D*)m_chart->series().at(1);
impl->setSecondaryAxisX(Qt::Checked == state);
}
void MainWindow::showAxisXChanged(int state)
{
ChartView2D* view2D = static_cast<ChartView2D *>(m_chart->views().at(0));
view2D->secondaryAxisX()->setVisible(Qt::Checked == state);
}
void MainWindow::showSecondaryAxisYChanged(int state)
{
ChartView2D* view2D = static_cast<ChartView2D *>(m_chart->views().at(0));
if (Qt::Checked != state)
view2D->secondaryAxisY()->setVisible(false);
else
showAxisYChanged(Qt::Checked);
ChartAxisTitle* titleY = view2D->axisY()->title();
Q_ASSERT(titleY != Q_NULL);
if (Qt::Checked == state)
{
view2D->secondaryAxisY()->title()->setText(tr("Series 2 Y"));
view2D->secondaryAxisY()->title()->setVisible(true);
titleY->setText(tr("Series 1 Y"));
titleY->setVisible(true);
}
else
{
titleY->setText(tr("Series 1 and 2 Y"));
titleY->setVisible(true);
}
ChartSeries2D* impl = (ChartSeries2D*)m_chart->series().at(1);
impl->setSecondaryAxisX(Qt::Checked == state);
}
void MainWindow::showAxisYChanged(int state)
{
ChartView2D* view2D = static_cast<ChartView2D *>(m_chart->views().at(0));
view2D->secondaryAxisY()->setVisible(Qt::Checked == state);
}
void MainWindow::updateAngleChanged(int)
{
updateValueParameters();
}
void MainWindow::mouseTrack(ChartHitInfo* hit)
{
const ViewList& listViews = m_chart->views();
if (hit == Q_NULL || listViews.count() == 0)
return;
ChartView2D* view2D = static_cast<ChartView2D*>(listViews.at(0));
QPoint pt = hit->hitPoint();
ChartAxis* axisXX = view2D->axisX();
Q_ASSERT(axisXX != Q_NULL);
qreal realXMarker = axisXX->valueFromPoint(pt);
int xValue = (int)floor(realXMarker);
bool redraw = false;
const int seriesCount = m_chart->series().count();
((AdvancedChart*)m_chart)->m_arMarkers.resize(seriesCount);
for (int i = 0; i < seriesCount; i++)
{
ChartSeries2D* series2D = (ChartSeries2D*)m_chart->series().at(i);
Q_ASSERT(series2D != Q_NULL);
const ChartDataPoint* dp1 = series2D->at(xValue);
const ChartDataPoint* dp2 = series2D->at(xValue + 1);
if (dp1 != Q_NULL && dp2 != Q_NULL)
{
ChartView2D* view = static_cast<ChartView2D *>(series2D->view());
ChartAxis* axisX = view->axisX();
ChartAxis* axisY = view->axisY();
qreal x1 = axisX->valueToPoint(dp1->valueX());
qreal x2 = axisX->valueToPoint(dp2->valueX());
qreal y1 = axisY->valueToPoint(dp1->valueY());
qreal y2 = axisY->valueToPoint(dp2->valueY());
QPoint pt1(x1, y1);
QPoint pt2(x2, y2);
QPoint ptMarker;
if (::qFabs((qreal)pt.x() - pt1.x()) < ::qFabs((qreal)pt.x() - pt2.x()))
ptMarker = pt1;
else
ptMarker = pt2;
if (((AdvancedChart*)m_chart)->m_arMarkers.size() < seriesCount || ((AdvancedChart*)m_chart)->m_arMarkers[i] != ptMarker)
{
((AdvancedChart*)m_chart)->m_arMarkers[i] = ptMarker;
if (i == 0)
((AdvancedChart*)m_chart)->m_XLine = ptMarker.x();
redraw = true;
}
}
}
if (redraw)
m_chart->repaint();
QCursor cursor = Qt::ArrowCursor;
QString strInfo;
switch (hit->hitInfo())
{
case ChartHitInfo::HitDataPoint:
{
strInfo = tr("Hovered Element: Data Point\nClick left mouse button to get additional information");
cursor = Qt::PointingHandCursor;
}
break;
case ChartHitInfo::HitChartArea:
strInfo = tr("Hovered Element: Chart Area");
break;
case ChartHitInfo::HitAxis:
case ChartHitInfo::HitAxisName:
{
ChartAxis* axis = Q_NULL;
QString strName = tr("NoName");
qreal value = 0.0;
for (int i = 0, count = listViews.count(); i < count && axis == Q_NULL; i++)
{
ChartView2D* view = static_cast<ChartView2D *>(listViews.at(i));
ChartAxis* axisX = view->axisX();
Q_ASSERT(axisX != Q_NULL);
ChartAxis* axisY = view->axisY();
Q_ASSERT(axisY != Q_NULL);
if (axisX->axisID() == hit->axisID1())
axis = axisX;
else if (axisY->axisID() == hit->axisID1())
axis = axisY;
else if (m_axisY1->axisID() == hit->axisID1())
axis = m_axisY1;
else if (m_axisY2->axisID() == hit->axisID1())
axis = m_axisY2;
if (axis != Q_NULL)
{
strName = axis->title()->text();
value = axis->valueFromPoint(pt);
}
if (hit->hitInfo() == ChartHitInfo::HitAxisName)
strInfo = QStringLiteral("Hovered Element: Axis Name\r\nAxis Name: %1").arg(strName);
else
strInfo = QStringLiteral("Hovered Element: Axis\r\nAxis Name: %1\r\nValue = %2").arg(strName).arg(value);
}
}
break;
case ChartHitInfo::HitTitle:
strInfo = tr("Hovered Element: Chart Title");
break;
case ChartHitInfo::HitView:
{
for (int i = 0, count = listViews.count(); i < count && strInfo.isEmpty(); i++)
{
ChartView2D* view = static_cast<ChartView2D*>(listViews.at(i));
ChartAxis* axisX = view->axis(hit->axisID1());
ChartAxis* axisY = view->axis(hit->axisID2());
if (axisX != Q_NULL && axisY != Q_NULL)
{
Q_ASSERT(axisX != Q_NULL);
Q_ASSERT(axisY != Q_NULL);
int valueX = (int)(axisX->valueFromPoint(pt) + 1.5);
qreal valueY = axisY->valueFromPoint(pt);
strInfo = QStringLiteral("Hovered Element: Chart View\r\nX Value: %1\r\nY Value: %2").arg(valueX).arg(valueY);
}
}
if (strInfo.isEmpty())
strInfo = tr("Hovered Element: Chart View");
}
break;
case ChartHitInfo::HitLegend:
strInfo = tr("Hovered Element: Legend");
break;
default:
strInfo = DEFAULT_INFO;
break;
}
if (!strInfo.isEmpty())
m_hitTestResult->setText(strInfo);
setCursor(cursor);
}
void MainWindow::mouseUp(ChartHitInfo* hit)
{
if (hit->mouseButton() == Qt::NoButton || hit->hitInfo() != ChartHitInfo::HitDataPoint)
return;
ChartSeries2D* dataTable = (ChartSeries2D*)m_chart->series().at(hit->index());
Q_ASSERT(dataTable != Q_NULL);
QString strInfo;
strInfo = QStringLiteral("Clicked on the Data Point:\r\n\nSeries Index: %1\r\nSeries Name: %2\r\nData Point Index: %3\r\nData Point Value: %4").
arg(hit->index()).arg(dataTable->name()).arg(hit->pointIndex()).arg(dataTable->at(hit->pointIndex())->valueY());
QMessageBox messageBox(QMessageBox::Information, qApp->applicationName(), QString(), QMessageBox::Ok, this);
messageBox.setInformativeText(strInfo);
messageBox.exec();
}