1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Charts module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 or (at your option) any later version
20** approved by the KDE Free Qt Foundation. The licenses are as published by
21** the Free Software Foundation and appearing in the file LICENSE.GPL3
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include <QtCharts/QBarCategoryAxis>
31#include <QtCharts/QCandlestickSeries>
32#include <QtCharts/QCandlestickSet>
33#include <QtCharts/QDateTimeAxis>
34#include <QtCharts/QHCandlestickModelMapper>
35#include <QtCharts/QValueAxis>
36#include <QtCore/QDateTime>
37#include <QtCore/QDebug>
38#include <QtCore/QRandomGenerator>
39#include <QtWidgets/QCheckBox>
40#include <QtWidgets/QComboBox>
41#include <QtWidgets/QDoubleSpinBox>
42#include <QtWidgets/QGridLayout>
43#include <QtWidgets/QHeaderView>
44#include <QtWidgets/QLabel>
45#include <QtWidgets/QPushButton>
46#include <QtWidgets/QTableView>
47#include "customtablemodel.h"
48#include "mainwidget.h"
49
50QT_CHARTS_USE_NAMESPACE
51
52MainWidget::MainWidget(QWidget *parent)
53 : QWidget(parent),
54 m_chart(new QChart()),
55 m_chartView(new QChartView(m_chart, this)),
56 m_axisX(nullptr),
57 m_axisY(nullptr),
58 m_maximumColumnWidth(-1.0),
59 m_minimumColumnWidth(5.0),
60 m_bodyOutlineVisible(true),
61 m_capsVisible(false),
62 m_bodyWidth(0.5),
63 m_capsWidth(0.5),
64 m_customIncreasingColor(false),
65 m_customDecreasingColor(false),
66 m_hModelMapper(new QHCandlestickModelMapper(this))
67{
68 m_chartView->setRenderHint(hint: QPainter::Antialiasing, enabled: false);
69
70 m_hModelMapper->setModel(new CustomTableModel(this));
71 m_hModelMapper->setTimestampColumn(0);
72 m_hModelMapper->setOpenColumn(1);
73 m_hModelMapper->setHighColumn(2);
74 m_hModelMapper->setLowColumn(3);
75 m_hModelMapper->setCloseColumn(4);
76
77 QGridLayout *mainLayout = new QGridLayout();
78 mainLayout->addLayout(createSeriesControlsLayout(), row: 0, column: 0);
79 mainLayout->addLayout(createSetsControlsLayout(), row: 1, column: 0);
80 mainLayout->addLayout(createCandlestickControlsLayout(), row: 2, column: 0);
81 mainLayout->addLayout(createMiscellaneousControlsLayout(), row: 3, column: 0);
82 mainLayout->addWidget(m_chartView, row: 0, column: 1, rowSpan: mainLayout->rowCount() + 1, columnSpan: 1);
83 mainLayout->addLayout(createModelMapperControlsLayout(), row: 0, column: 2, rowSpan: mainLayout->rowCount(), columnSpan: 1);
84 setLayout(mainLayout);
85
86 addSeries();
87}
88
89MainWidget::~MainWidget()
90{
91}
92
93QGridLayout *MainWidget::createSeriesControlsLayout()
94{
95 QGridLayout *layout = new QGridLayout();
96 int row = 0;
97
98 layout->addWidget(new QLabel(QStringLiteral("Series controls:")), row, column: 0, Qt::AlignLeft);
99
100 QPushButton *addSeriesButton = new QPushButton(QStringLiteral("Add a series"));
101 connect(sender: addSeriesButton, SIGNAL(clicked(bool)), receiver: this, SLOT(addSeries()));
102 layout->addWidget(addSeriesButton, row: row++, column: 1, Qt::AlignLeft);
103
104 QPushButton *removeSeriesButton = new QPushButton(QStringLiteral("Remove a series"));
105 connect(sender: removeSeriesButton, SIGNAL(clicked(bool)), receiver: this, SLOT(removeSeries()));
106 layout->addWidget(removeSeriesButton, row: row++, column: 1, Qt::AlignLeft);
107
108 QPushButton *removeAllSeriesButton = new QPushButton(QStringLiteral("Remove all series"));
109 connect(sender: removeAllSeriesButton, SIGNAL(clicked(bool)), receiver: this, SLOT(removeAllSeries()));
110 layout->addWidget(removeAllSeriesButton, row: row++, column: 1, Qt::AlignLeft);
111
112 return layout;
113}
114
115QGridLayout *MainWidget::createSetsControlsLayout()
116{
117 QGridLayout *layout = new QGridLayout();
118 int row = 0;
119
120 layout->addWidget(new QLabel(QStringLiteral("Sets controls:")), row, column: 0, Qt::AlignLeft);
121
122 QPushButton *addSetButton = new QPushButton(QStringLiteral("Add a set"));
123 connect(sender: addSetButton, SIGNAL(clicked(bool)), receiver: this, SLOT(addSet()));
124 layout->addWidget(addSetButton, row: row++, column: 1, Qt::AlignLeft);
125
126 QPushButton *insertSetButton = new QPushButton(QStringLiteral("Insert a set"));
127 connect(sender: insertSetButton, SIGNAL(clicked(bool)), receiver: this, SLOT(insertSet()));
128 layout->addWidget(insertSetButton, row: row++, column: 1, Qt::AlignLeft);
129
130 QPushButton *removeSetButton = new QPushButton(QStringLiteral("Remove a set"));
131 connect(sender: removeSetButton, SIGNAL(clicked(bool)), receiver: this, SLOT(removeSet()));
132 layout->addWidget(removeSetButton, row: row++, column: 1, Qt::AlignLeft);
133
134 QPushButton *removeAllSetsButton = new QPushButton(QStringLiteral("Remove all sets"));
135 connect(sender: removeAllSetsButton, SIGNAL(clicked(bool)), receiver: this, SLOT(removeAllSets()));
136 layout->addWidget(removeAllSetsButton, row: row++, column: 1, Qt::AlignLeft);
137
138 return layout;
139}
140
141QGridLayout *MainWidget::createCandlestickControlsLayout()
142{
143 QGridLayout *layout = new QGridLayout();
144 int row = 0;
145
146 layout->addWidget(new QLabel(QStringLiteral("Maximum column width:")), row, column: 0, Qt::AlignLeft);
147 QDoubleSpinBox *maximumColumnWidthSpinBox = new QDoubleSpinBox();
148 maximumColumnWidthSpinBox->setRange(min: -1.0, max: 1024.0);
149 maximumColumnWidthSpinBox->setDecimals(0);
150 maximumColumnWidthSpinBox->setValue(m_maximumColumnWidth);
151 maximumColumnWidthSpinBox->setSingleStep(1.0);
152 connect(sender: maximumColumnWidthSpinBox, SIGNAL(valueChanged(double)),
153 receiver: this, SLOT(changeMaximumColumnWidth(double)));
154 layout->addWidget(maximumColumnWidthSpinBox, row: row++, column: 1, Qt::AlignLeft);
155
156 layout->addWidget(new QLabel(QStringLiteral("Minimum column width:")), row, column: 0, Qt::AlignLeft);
157 QDoubleSpinBox *minimumColumnWidthSpinBox = new QDoubleSpinBox();
158 minimumColumnWidthSpinBox->setRange(min: -1.0, max: 1024.0);
159 minimumColumnWidthSpinBox->setDecimals(0);
160 minimumColumnWidthSpinBox->setValue(m_minimumColumnWidth);
161 minimumColumnWidthSpinBox->setSingleStep(1.0);
162 connect(sender: minimumColumnWidthSpinBox, SIGNAL(valueChanged(double)),
163 receiver: this, SLOT(changeMinimumColumnWidth(double)));
164 layout->addWidget(minimumColumnWidthSpinBox, row: row++, column: 1, Qt::AlignLeft);
165
166 QCheckBox *bodyOutlineVisible = new QCheckBox(QStringLiteral("Body outline visible"));
167 connect(sender: bodyOutlineVisible, SIGNAL(toggled(bool)), receiver: this, SLOT(bodyOutlineVisibleToggled(bool)));
168 bodyOutlineVisible->setChecked(m_bodyOutlineVisible);
169 layout->addWidget(bodyOutlineVisible, row: row++, column: 0, Qt::AlignLeft);
170
171 QCheckBox *capsVisible = new QCheckBox(QStringLiteral("Caps visible"));
172 connect(sender: capsVisible, SIGNAL(toggled(bool)), receiver: this, SLOT(capsVisibleToggled(bool)));
173 capsVisible->setChecked(m_capsVisible);
174 layout->addWidget(capsVisible, row: row++, column: 0, Qt::AlignLeft);
175
176 layout->addWidget(new QLabel(QStringLiteral("Candlestick body width:")), row, column: 0, Qt::AlignLeft);
177 QDoubleSpinBox *bodyWidthSpinBox = new QDoubleSpinBox();
178 bodyWidthSpinBox->setRange(min: -1.0, max: 2.0);
179 bodyWidthSpinBox->setValue(m_bodyWidth);
180 bodyWidthSpinBox->setSingleStep(0.1);
181 connect(sender: bodyWidthSpinBox, SIGNAL(valueChanged(double)), receiver: this, SLOT(changeBodyWidth(double)));
182 layout->addWidget(bodyWidthSpinBox, row: row++, column: 1, Qt::AlignLeft);
183
184 layout->addWidget(new QLabel(QStringLiteral("Candlestick caps width:")), row, column: 0, Qt::AlignLeft);
185 QDoubleSpinBox *capsWidthSpinBox = new QDoubleSpinBox();
186 capsWidthSpinBox->setRange(min: -1.0, max: 2.0);
187 capsWidthSpinBox->setValue(m_capsWidth);
188 capsWidthSpinBox->setSingleStep(0.1);
189 connect(sender: capsWidthSpinBox, SIGNAL(valueChanged(double)), receiver: this, SLOT(changeCapsWidth(double)));
190 layout->addWidget(capsWidthSpinBox, row: row++, column: 1, Qt::AlignLeft);
191
192 QCheckBox *increasingColor = new QCheckBox(QStringLiteral("Custom increasing color (only S1)"));
193 connect(sender: increasingColor, SIGNAL(toggled(bool)), receiver: this, SLOT(customIncreasingColorToggled(bool)));
194 increasingColor->setChecked(m_customIncreasingColor);
195 layout->addWidget(increasingColor, row: row++, column: 0, rowSpan: 1, columnSpan: 2, Qt::AlignLeft);
196
197 QCheckBox *decreasingColor = new QCheckBox(QStringLiteral("Custom decreasing color (only S1)"));
198 connect(sender: decreasingColor, SIGNAL(toggled(bool)), receiver: this, SLOT(customDecreasingColorToggled(bool)));
199 decreasingColor->setChecked(m_customDecreasingColor);
200 layout->addWidget(decreasingColor, row: row++, column: 0, rowSpan: 1, columnSpan: 2, Qt::AlignLeft);
201
202 return layout;
203}
204
205QGridLayout *MainWidget::createMiscellaneousControlsLayout()
206{
207 QGridLayout *layout = new QGridLayout();
208 int row = 0;
209
210 layout->addWidget(new QLabel(QStringLiteral("Miscellaneous:")), row, column: 0, Qt::AlignLeft);
211
212 QCheckBox *antialiasingCheckBox = new QCheckBox(QStringLiteral("Antialiasing"));
213 connect(sender: antialiasingCheckBox, SIGNAL(toggled(bool)), receiver: this, SLOT(antialiasingToggled(bool)));
214 antialiasingCheckBox->setChecked(false);
215 layout->addWidget(antialiasingCheckBox, row: row++, column: 1, Qt::AlignLeft);
216
217 QCheckBox *animationCheckBox = new QCheckBox(QStringLiteral("Animation"));
218 connect(sender: animationCheckBox, SIGNAL(toggled(bool)), receiver: this, SLOT(animationToggled(bool)));
219 animationCheckBox->setChecked(false);
220 layout->addWidget(animationCheckBox, row: row++, column: 1, Qt::AlignLeft);
221
222 QCheckBox *legendCheckBox = new QCheckBox(QStringLiteral("Legend"));
223 connect(sender: legendCheckBox, SIGNAL(toggled(bool)), receiver: this, SLOT(legendToggled(bool)));
224 legendCheckBox->setChecked(true);
225 layout->addWidget(legendCheckBox, row: row++, column: 1, Qt::AlignLeft);
226
227 QCheckBox *titleCheckBox = new QCheckBox(QStringLiteral("Title"));
228 connect(sender: titleCheckBox, SIGNAL(toggled(bool)), receiver: this, SLOT(titleToggled(bool)));
229 titleCheckBox->setChecked(true);
230 layout->addWidget(titleCheckBox, row: row++, column: 1, Qt::AlignLeft);
231
232 layout->addWidget(new QLabel(QStringLiteral("Chart theme:")), row, column: 0, Qt::AlignLeft);
233 QComboBox *chartThemeComboBox = new QComboBox();
234 chartThemeComboBox->addItem(QStringLiteral("Light"));
235 chartThemeComboBox->addItem(QStringLiteral("Blue Cerulean"));
236 chartThemeComboBox->addItem(QStringLiteral("Dark"));
237 chartThemeComboBox->addItem(QStringLiteral("Brown Sand"));
238 chartThemeComboBox->addItem(QStringLiteral("Blue Ncs"));
239 chartThemeComboBox->addItem(QStringLiteral("High Contrast"));
240 chartThemeComboBox->addItem(QStringLiteral("Blue Icy"));
241 chartThemeComboBox->addItem(QStringLiteral("Qt"));
242 connect(sender: chartThemeComboBox,SIGNAL(currentIndexChanged(int)),receiver: this,SLOT(changeChartTheme(int)));
243 layout->addWidget(chartThemeComboBox, row: row++, column: 1, Qt::AlignLeft);
244
245 layout->addWidget(new QLabel(QStringLiteral("Axis X:")), row, column: 0, Qt::AlignLeft);
246 QComboBox *axisXComboBox = new QComboBox();
247 axisXComboBox->addItem(QStringLiteral("BarCategory"));
248 axisXComboBox->addItem(QStringLiteral("DateTime"));
249 axisXComboBox->addItem(QStringLiteral("Value"));
250 connect(sender: axisXComboBox, SIGNAL(currentIndexChanged(int)), receiver: this, SLOT(changeAxisX(int)));
251 layout->addWidget(axisXComboBox, row: row++, column: 1, Qt::AlignLeft);
252
253 return layout;
254}
255
256QGridLayout *MainWidget::createModelMapperControlsLayout()
257{
258 QGridLayout *layout = new QGridLayout();
259 int row = 0;
260
261 layout->addWidget(new QLabel(QStringLiteral("First series:")), row, column: 0, Qt::AlignLeft);
262
263 QPushButton *attachModelMapperButton = new QPushButton(QStringLiteral("Attach model mapper"));
264 connect(sender: attachModelMapperButton, SIGNAL(clicked(bool)), receiver: this, SLOT(attachModelMapper()));
265 layout->addWidget(attachModelMapperButton, row: row++, column: 1, Qt::AlignLeft);
266
267 QPushButton *detachModelMappeButton = new QPushButton(QStringLiteral("Detach model mapper"));
268 connect(sender: detachModelMappeButton, SIGNAL(clicked(bool)), receiver: this, SLOT(detachModelMapper()));
269 layout->addWidget(detachModelMappeButton, row: row++, column: 1, Qt::AlignLeft);
270
271 QTableView *tableView = new QTableView();
272 tableView->setMinimumSize(minw: 320, minh: 480);
273 tableView->setMaximumSize(maxw: 320, maxh: 480);
274 tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
275 tableView->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
276 Q_ASSERT_X(m_hModelMapper->model(), Q_FUNC_INFO, "Model is not initialized");
277 tableView->setModel(m_hModelMapper->model());
278 layout->addWidget(tableView, row: row++, column: 0, rowSpan: 1, columnSpan: 2, Qt::AlignLeft);
279
280 layout->addItem(item: new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding), row: row++, column: 0);
281
282 return layout;
283}
284
285qreal MainWidget::randomValue(int min, int max) const
286{
287 if (min > max)
288 qSwap(value1&: min, value2&: max);
289 return QRandomGenerator::global()->bounded(lowest: min, highest: max);
290}
291
292QCandlestickSet *MainWidget::randomSet(qreal timestamp)
293{
294 QCandlestickSet *set = new QCandlestickSet(timestamp);
295 set->setOpen(randomValue(min: 4, max: 11));
296 set->setHigh(randomValue(min: 12, max: 15));
297 set->setLow(randomValue(min: 0, max: 3));
298 set->setClose(randomValue(min: 4, max: 11));
299
300 return set;
301}
302
303void MainWidget::updateAxes()
304{
305 if (m_chart->axes().isEmpty())
306 m_chart->createDefaultAxes();
307
308 QCandlestickSeries *series;
309 if (!m_chart->series().isEmpty())
310 series = qobject_cast<QCandlestickSeries *>(object: m_chart->series().at(i: 0));
311 else
312 series = nullptr;
313
314 m_axisX = m_chart->axes(orientation: Qt::Horizontal).first();
315 if (series && !series->sets().isEmpty()) {
316 if (m_axisX->type() == QAbstractAxis::AxisTypeBarCategory) {
317 QBarCategoryAxis *axisX = qobject_cast<QBarCategoryAxis *>(object: m_axisX);
318 QStringList categories;
319 for (int i = 0; i < series->sets().count(); ++i)
320 categories.append(t: QString::number(i));
321 axisX->setCategories(categories);
322 } else { // QAbstractAxis::AxisTypeDateTime || QAbstractAxis::AxisTypeValue
323 qreal msInMonth = 31.0 * 24.0 * 60.0 * 60.0 * 1000.0;
324 qreal min = series->sets().first()->timestamp() - msInMonth;
325 qreal max = series->sets().last()->timestamp() + msInMonth;
326 QDateTime minDateTime = QDateTime::fromMSecsSinceEpoch(msecs: min);
327 QDateTime maxDateTime = QDateTime::fromMSecsSinceEpoch(msecs: max);
328
329 if (m_axisX->type() == QAbstractAxis::AxisTypeDateTime)
330 m_axisX->setRange(min: minDateTime, max: maxDateTime);
331 else
332 m_axisX->setRange(min, max);
333 }
334 }
335
336 m_axisY = m_chart->axes(orientation: Qt::Vertical).first();
337 m_axisY->setMax(15);
338 m_axisY->setMin(0);
339}
340
341void MainWidget::addSeries()
342{
343 if (m_chart->series().count() > 9) {
344 qDebug() << "Maximum series count is 10";
345 return;
346 }
347
348 QCandlestickSeries *series = new QCandlestickSeries();
349 series->setName(QStringLiteral("S%1").arg(a: m_chart->series().count() + 1));
350 series->setMaximumColumnWidth(m_maximumColumnWidth);
351 series->setMinimumColumnWidth(m_minimumColumnWidth);
352 series->setBodyOutlineVisible(m_bodyOutlineVisible);
353 series->setBodyWidth(m_bodyWidth);
354 series->setCapsVisible(m_capsVisible);
355 series->setCapsWidth(m_capsWidth);
356
357 if (m_chart->series().isEmpty()) {
358 if (m_customIncreasingColor)
359 series->setIncreasingColor(QColor(Qt::green));
360 if (m_customDecreasingColor)
361 series->setDecreasingColor(QColor(Qt::red));
362
363 for (int month = 1; month <= 12; ++month) {
364 QDateTime dateTime;
365 dateTime.setDate(QDate(QDateTime::currentDateTime().date().year(), month, 1));
366 dateTime.setTime(QTime(12, 34, 56, 789));
367
368 QCandlestickSet *set = randomSet(timestamp: dateTime.toMSecsSinceEpoch());
369 series->append(set);
370 }
371 } else {
372 QCandlestickSeries *s = qobject_cast<QCandlestickSeries *>(object: m_chart->series().at(i: 0));
373 for (int i = 0; i < s->sets().count(); ++i) {
374 QCandlestickSet *set = randomSet(timestamp: s->sets().at(i)->timestamp());
375 series->append(set);
376 }
377 }
378
379 m_chart->addSeries(series);
380
381 updateAxes();
382 if (!series->attachedAxes().contains(t: m_axisX))
383 series->attachAxis(axis: m_axisX);
384 if (!series->attachedAxes().contains(t: m_axisY))
385 series->attachAxis(axis: m_axisY);
386}
387
388void MainWidget::removeSeries()
389{
390 if (m_chart->series().isEmpty()) {
391 qDebug() << "Create a series first";
392 return;
393 }
394
395 if (m_chart->series().count() == 1)
396 detachModelMapper();
397
398 QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(object: m_chart->series().last());
399 m_chart->removeSeries(series);
400 delete series;
401 series = nullptr;
402}
403
404void MainWidget::removeAllSeries()
405{
406 if (m_chart->series().isEmpty()) {
407 qDebug() << "Create a series first";
408 return;
409 }
410
411 detachModelMapper();
412
413 m_chart->removeAllSeries();
414}
415
416void MainWidget::addSet()
417{
418 if (m_chart->series().isEmpty()) {
419 qDebug() << "Create a series first";
420 return;
421 }
422
423 foreach (QAbstractSeries *s, m_chart->series()) {
424 QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(object: s);
425
426 QDateTime dateTime;
427 if (series->count()) {
428 dateTime.setMSecsSinceEpoch(series->sets().last()->timestamp());
429 dateTime = dateTime.addMonths(months: 1);
430 } else {
431 dateTime.setDate(QDate(QDateTime::currentDateTime().date().year(), 1, 1));
432 dateTime.setTime(QTime(12, 34, 56, 789));
433 }
434
435 QCandlestickSet *set = randomSet(timestamp: dateTime.toMSecsSinceEpoch());
436 series->append(set);
437 }
438
439 updateAxes();
440}
441
442void MainWidget::insertSet()
443{
444 if (m_chart->series().isEmpty()) {
445 qDebug() << "Create a series first";
446 return;
447 }
448
449 foreach (QAbstractSeries *s, m_chart->series()) {
450 QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(object: s);
451
452 QDateTime dateTime;
453 if (series->count()) {
454 dateTime.setMSecsSinceEpoch(series->sets().first()->timestamp());
455 dateTime = dateTime.addMonths(months: -1);
456 } else {
457 dateTime.setDate(QDate(QDateTime::currentDateTime().date().year(), 1, 1));
458 dateTime.setTime(QTime(12, 34, 56, 789));
459 }
460
461 QCandlestickSet *set = randomSet(timestamp: dateTime.toMSecsSinceEpoch());
462 series->insert(index: 0, set);
463 }
464
465 updateAxes();
466}
467
468void MainWidget::removeSet()
469{
470 if (m_chart->series().isEmpty()) {
471 qDebug() << "Create a series first";
472 return;
473 }
474
475 foreach (QAbstractSeries *s, m_chart->series()) {
476 QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(object: s);
477 if (series->sets().isEmpty())
478 qDebug() << "Create a set first";
479 else
480 series->remove(set: series->sets().last());
481 }
482
483 updateAxes();
484}
485
486void MainWidget::removeAllSets()
487{
488 if (m_chart->series().isEmpty()) {
489 qDebug() << "Create a series first";
490 return;
491 }
492
493 foreach (QAbstractSeries *s, m_chart->series()) {
494 QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(object: s);
495 if (series->sets().isEmpty())
496 qDebug() << "Create a set first";
497 else
498 series->clear();
499 }
500
501 updateAxes();
502}
503
504void MainWidget::changeMaximumColumnWidth(double width)
505{
506 m_maximumColumnWidth = width;
507 foreach (QAbstractSeries *s, m_chart->series()) {
508 QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(object: s);
509 series->setMaximumColumnWidth(m_maximumColumnWidth);
510 }
511}
512
513void MainWidget::changeMinimumColumnWidth(double width)
514{
515 m_minimumColumnWidth = width;
516 foreach (QAbstractSeries *s, m_chart->series()) {
517 QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(object: s);
518 series->setMinimumColumnWidth(m_minimumColumnWidth);
519 }
520}
521
522void MainWidget::bodyOutlineVisibleToggled(bool visible)
523{
524 m_bodyOutlineVisible = visible;
525 foreach (QAbstractSeries *s, m_chart->series()) {
526 QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(object: s);
527 series->setBodyOutlineVisible(m_bodyOutlineVisible);
528 }
529}
530
531void MainWidget::capsVisibleToggled(bool visible)
532{
533 m_capsVisible = visible;
534 foreach (QAbstractSeries *s, m_chart->series()) {
535 QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(object: s);
536 series->setCapsVisible(m_capsVisible);
537 }
538}
539
540void MainWidget::changeBodyWidth(double width)
541{
542 m_bodyWidth = width;
543 foreach (QAbstractSeries *s, m_chart->series()) {
544 QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(object: s);
545 series->setBodyWidth(m_bodyWidth);
546 }
547}
548
549void MainWidget::changeCapsWidth(double width)
550{
551 m_capsWidth = width;
552 foreach (QAbstractSeries *s, m_chart->series()) {
553 QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(object: s);
554 series->setCapsWidth(m_capsWidth);
555 }
556}
557
558void MainWidget::customIncreasingColorToggled(bool custom)
559{
560 m_customIncreasingColor = custom;
561
562 if (m_chart->series().isEmpty())
563 return;
564
565 QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(object: m_chart->series().at(i: 0));
566 if (series) {
567 QColor color = m_customIncreasingColor ? QColor(Qt::green) : QColor();
568 series->setIncreasingColor(color);
569 }
570}
571
572void MainWidget::customDecreasingColorToggled(bool custom)
573{
574 m_customDecreasingColor = custom;
575
576 if (m_chart->series().isEmpty())
577 return;
578
579 QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(object: m_chart->series().at(i: 0));
580 if (series) {
581 QColor color = m_customDecreasingColor ? QColor(Qt::red) : QColor();
582 series->setDecreasingColor(color);
583 }
584}
585
586void MainWidget::antialiasingToggled(bool enabled)
587{
588 m_chartView->setRenderHint(hint: QPainter::Antialiasing, enabled);
589}
590
591void MainWidget::animationToggled(bool enabled)
592{
593 if (enabled)
594 m_chart->setAnimationOptions(QChart::SeriesAnimations);
595 else
596 m_chart->setAnimationOptions(QChart::NoAnimation);
597}
598
599void MainWidget::legendToggled(bool visible)
600{
601 m_chart->legend()->setVisible(visible);
602 if (visible)
603 m_chart->legend()->setAlignment(Qt::AlignBottom);
604}
605
606void MainWidget::titleToggled(bool visible)
607{
608 if (visible)
609 m_chart->setTitle(QStringLiteral("Candlestick Chart"));
610 else
611 m_chart->setTitle(QString());
612}
613
614void MainWidget::changeChartTheme(int themeIndex)
615{
616 if (themeIndex < QChart::ChartThemeLight || themeIndex > QChart::ChartThemeQt) {
617 qDebug() << "Invalid chart theme index:" << themeIndex;
618 return;
619 }
620
621 m_chart->setTheme((QChart::ChartTheme)(themeIndex));
622}
623
624void MainWidget::changeAxisX(int axisXIndex)
625{
626 if (m_axisX) {
627 m_chart->removeAxis(axis: m_axisX);
628 delete m_axisX;
629 }
630
631 switch (axisXIndex) {
632 case 0:
633 m_axisX = new QBarCategoryAxis();
634 break;
635 case 1:
636 m_axisX = new QDateTimeAxis();
637 break;
638 case 2:
639 m_axisX = new QValueAxis();
640 break;
641 default:
642 qDebug() << "Invalid axis x index:" << axisXIndex;
643 return;
644 }
645
646 m_chart->addAxis(axis: m_axisX, alignment: Qt::AlignBottom);
647
648 updateAxes();
649
650 foreach (QAbstractSeries *series, m_chart->series())
651 series->attachAxis(axis: m_axisX);
652}
653
654void MainWidget::attachModelMapper()
655{
656 if (m_hModelMapper->series()) {
657 qDebug() << "Model mapper is already attached";
658 return;
659 }
660
661 if (m_chart->series().isEmpty())
662 addSeries();
663
664 QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(object: m_chart->series().at(i: 0));
665 Q_ASSERT(series);
666 series->setName(QStringLiteral("SWMM")); // Series With Model Mapper
667
668 CustomTableModel *model = qobject_cast<CustomTableModel *>(object: m_hModelMapper->model());
669 foreach (QCandlestickSet *set, series->sets())
670 model->addRow(set);
671
672 m_hModelMapper->setFirstSetRow(0);
673 m_hModelMapper->setLastSetRow(model->rowCount() - 1);
674 m_hModelMapper->setSeries(series);
675}
676
677void MainWidget::detachModelMapper()
678{
679 if (!m_hModelMapper->series())
680 return;
681
682 QCandlestickSeries *series = qobject_cast<QCandlestickSeries *>(object: m_hModelMapper->series());
683 Q_ASSERT(series);
684 series->setName(QStringLiteral("S1"));
685
686 m_hModelMapper->setSeries(nullptr);
687 m_hModelMapper->setFirstSetRow(-1);
688 m_hModelMapper->setLastSetRow(-1);
689
690 CustomTableModel *model = qobject_cast<CustomTableModel *>(object: m_hModelMapper->model());
691 model->clearRows();
692}
693

source code of qtcharts/tests/manual/candlesticktester/mainwidget.cpp