@@ -27,6 +27,7 | |||
|
27 | 27 | #include <QBarSet> |
|
28 | 28 | #include <QBarSeries> |
|
29 | 29 | #include <QLegend> |
|
30 | #include <QFormLayout> | |
|
30 | 31 | |
|
31 | 32 | QTCOMMERCIALCHART_USE_NAMESPACE |
|
32 | 33 | |
@@ -49,25 +50,52 MainWidget::MainWidget(QWidget *parent) : | |||
|
49 | 50 | connect(removeBarsetButton, SIGNAL(clicked()), this, SLOT(removeBarset())); |
|
50 | 51 | m_buttonLayout->addWidget(removeBarsetButton, 3, 0); |
|
51 | 52 | |
|
53 | QPushButton *leftButton = new QPushButton("Align legend left"); | |
|
54 | connect(leftButton, SIGNAL(clicked()), this, SLOT(setLegendLeft())); | |
|
55 | m_buttonLayout->addWidget(leftButton, 4, 0); | |
|
56 | ||
|
57 | QPushButton *rightButton = new QPushButton("Align legend right"); | |
|
58 | connect(rightButton, SIGNAL(clicked()), this, SLOT(setLegendRight())); | |
|
59 | m_buttonLayout->addWidget(rightButton, 5, 0); | |
|
60 | ||
|
61 | QPushButton *topButton = new QPushButton("Align legend top"); | |
|
62 | connect(topButton, SIGNAL(clicked()), this, SLOT(setLegendTop())); | |
|
63 | m_buttonLayout->addWidget(topButton, 6, 0); | |
|
64 | ||
|
65 | QPushButton *bottomButton = new QPushButton("Align legend bottom"); | |
|
66 | connect(bottomButton, SIGNAL(clicked()), this, SLOT(setLegendBottom())); | |
|
67 | m_buttonLayout->addWidget(bottomButton, 7, 0); | |
|
68 | ||
|
69 | m_legendPosX = new QDoubleSpinBox(); | |
|
70 | m_legendPosY = new QDoubleSpinBox(); | |
|
71 | m_legendWidth = new QDoubleSpinBox(); | |
|
72 | m_legendHeight = new QDoubleSpinBox(); | |
|
73 | ||
|
74 | connect(m_legendPosX, SIGNAL(valueChanged(double)), this, SLOT(updateLegendLayout())); | |
|
75 | connect(m_legendPosY, SIGNAL(valueChanged(double)), this, SLOT(updateLegendLayout())); | |
|
76 | connect(m_legendWidth, SIGNAL(valueChanged(double)), this, SLOT(updateLegendLayout())); | |
|
77 | connect(m_legendHeight, SIGNAL(valueChanged(double)), this, SLOT(updateLegendLayout())); | |
|
78 | ||
|
79 | QFormLayout* legendLayout = new QFormLayout(); | |
|
80 | legendLayout->addRow("Horizontal position", m_legendPosX); | |
|
81 | legendLayout->addRow("Vertical position", m_legendPosY); | |
|
82 | legendLayout->addRow("Width", m_legendWidth); | |
|
83 | legendLayout->addRow("Height", m_legendHeight); | |
|
84 | m_legendSettings = new QGroupBox("Detached legend"); | |
|
85 | m_legendSettings->setLayout(legendLayout); | |
|
86 | m_buttonLayout->addWidget(m_legendSettings); | |
|
87 | m_legendSettings->setVisible(false); | |
|
88 | ||
|
52 | 89 | // Create chart view with the chart |
|
53 | 90 | //![1] |
|
54 | 91 | m_chart = new QChart(); |
|
55 | 92 | m_chartView = new QChartView(m_chart, this); |
|
56 | m_chartView->setRubberBand(QChartView::HorizonalRubberBand); | |
|
57 | 93 | //![1] |
|
58 | 94 | |
|
59 | // Create custom scene and view, where detached legend will be drawn | |
|
60 | //![2] | |
|
61 | m_customView = new QGraphicsView(this); | |
|
62 | m_customScene = new QGraphicsScene(this); | |
|
63 | m_customView->setScene(m_customScene); | |
|
64 | //![2] | |
|
65 | ||
|
66 | 95 | // Create layout for grid and detached legend |
|
67 | 96 | m_mainLayout = new QGridLayout(); |
|
68 | 97 | m_mainLayout->addLayout(m_buttonLayout, 0, 0); |
|
69 | 98 | m_mainLayout->addWidget(m_chartView, 0, 1, 3, 1); |
|
70 | m_mainLayout->addWidget(m_customView, 0, 2, 3, 1); | |
|
71 | 99 | setLayout(m_mainLayout); |
|
72 | 100 | |
|
73 | 101 | createSeries(); |
@@ -93,43 +121,61 void MainWidget::createSeries() | |||
|
93 | 121 | //![3] |
|
94 | 122 | } |
|
95 | 123 | |
|
124 | void MainWidget::showLegendSpinbox() | |
|
125 | { | |
|
126 | m_legendSettings->setVisible(true); | |
|
127 | QRectF chartViewRect = m_chartView->rect(); | |
|
128 | QRectF legendRect = m_chart->legend()->boundingRect(); | |
|
129 | ||
|
130 | m_legendPosX->setMinimum(0); | |
|
131 | m_legendPosX->setMaximum(chartViewRect.width()); | |
|
132 | m_legendPosX->setValue(150); | |
|
133 | ||
|
134 | m_legendPosY->setMinimum(0); | |
|
135 | m_legendPosY->setMaximum(chartViewRect.height()); | |
|
136 | m_legendPosY->setValue(150); | |
|
137 | ||
|
138 | m_legendWidth->setMinimum(0); | |
|
139 | m_legendWidth->setMaximum(chartViewRect.width()); | |
|
140 | m_legendWidth->setValue(150); | |
|
141 | ||
|
142 | m_legendHeight->setMinimum(0); | |
|
143 | m_legendHeight->setMaximum(chartViewRect.height()); | |
|
144 | m_legendHeight->setValue(64); | |
|
145 | } | |
|
146 | ||
|
147 | void MainWidget::hideLegendSpinbox() | |
|
148 | { | |
|
149 | m_legendSettings->setVisible(false); | |
|
150 | } | |
|
151 | ||
|
152 | ||
|
96 | 153 | void MainWidget::detachLegend() |
|
97 | 154 | { |
|
98 | // Detach legend from chart and | |
|
99 | // put legend to our custom scene | |
|
100 | 155 | //![4] |
|
101 | 156 | QLegend *legend = m_chart->legend(); |
|
102 | 157 | legend->detachFromChart(); |
|
103 | legend->setGeometry(m_customView->rect()); | |
|
104 | m_customScene->addItem(legend); | |
|
158 | ||
|
159 | m_chart->legend()->setBackgroundVisible(true); | |
|
160 | m_chart->legend()->setBrush(QBrush(QColor(128,128,128,128))); | |
|
105 | 161 | //![4] |
|
106 | 162 | |
|
107 | // This forces redraw | |
|
108 | QSize delta(1,1); | |
|
109 | resize(size() + delta); | |
|
110 | resize(size() - delta); | |
|
163 | showLegendSpinbox(); | |
|
164 | updateLegendLayout(); | |
|
165 | update(); | |
|
111 | 166 | } |
|
112 | 167 | |
|
113 | 168 | |
|
114 | 169 | void MainWidget::attachLegend() |
|
115 | 170 | { |
|
116 | // Remove legend from custom scene and put it back to chartview scene. | |
|
117 | // Attach legend back to chart, so that layout works. | |
|
118 | ||
|
119 | 171 | //![5] |
|
120 | 172 | QLegend *legend = m_chart->legend(); |
|
121 | ||
|
122 | if (m_customScene->items().contains(legend)) { | |
|
123 | m_customScene->removeItem(legend); | |
|
124 | m_chartView->scene()->addItem(legend); | |
|
125 | legend->attachToChart(); | |
|
126 | } | |
|
173 | legend->attachToChart(); | |
|
174 | m_chart->legend()->setBackgroundVisible(false); | |
|
127 | 175 | //![5] |
|
128 | 176 | |
|
129 | // This forces redraw | |
|
130 | QSize delta(1,1); | |
|
131 | resize(size() + delta); | |
|
132 | resize(size() - delta); | |
|
177 | hideLegendSpinbox(); | |
|
178 | update(); | |
|
133 | 179 | } |
|
134 | 180 | |
|
135 | 181 | void MainWidget::addBarset() |
@@ -147,3 +193,32 void MainWidget::removeBarset() | |||
|
147 | 193 | m_series->remove(sets.at(sets.count()-1)); |
|
148 | 194 | } |
|
149 | 195 | } |
|
196 | ||
|
197 | void MainWidget::setLegendLeft() | |
|
198 | { | |
|
199 | m_chart->legend()->setAlignment(Qt::AlignLeft); | |
|
200 | } | |
|
201 | ||
|
202 | void MainWidget::setLegendRight() | |
|
203 | { | |
|
204 | m_chart->legend()->setAlignment(Qt::AlignRight); | |
|
205 | } | |
|
206 | ||
|
207 | void MainWidget::setLegendTop() | |
|
208 | { | |
|
209 | m_chart->legend()->setAlignment(Qt::AlignTop); | |
|
210 | } | |
|
211 | ||
|
212 | void MainWidget::setLegendBottom() | |
|
213 | { | |
|
214 | m_chart->legend()->setAlignment(Qt::AlignBottom); | |
|
215 | } | |
|
216 | ||
|
217 | void MainWidget::updateLegendLayout() | |
|
218 | { | |
|
219 | m_chart->legend()->setGeometry(m_legendPosX->value() | |
|
220 | ,m_legendPosY->value() | |
|
221 | ,m_legendWidth->value() | |
|
222 | ,m_legendHeight->value()); | |
|
223 | m_chart->legend()->update(); | |
|
224 | } |
@@ -28,6 +28,8 | |||
|
28 | 28 | #include <QGraphicsWidget> |
|
29 | 29 | #include <QGridLayout> |
|
30 | 30 | #include <QGraphicsGridLayout> |
|
31 | #include <QDoubleSpinBox> | |
|
32 | #include <QGroupBox> | |
|
31 | 33 | |
|
32 | 34 | QTCOMMERCIALCHART_USE_NAMESPACE |
|
33 | 35 | |
@@ -36,9 +38,10 class MainWidget : public QWidget | |||
|
36 | 38 | Q_OBJECT |
|
37 | 39 | public: |
|
38 | 40 | explicit MainWidget(QWidget *parent = 0); |
|
39 | ||
|
40 | 41 | void createSeries(); |
|
41 | ||
|
42 | void showLegendSpinbox(); | |
|
43 | void hideLegendSpinbox(); | |
|
44 | ||
|
42 | 45 | signals: |
|
43 | 46 | |
|
44 | 47 | public slots: |
@@ -47,6 +50,13 public slots: | |||
|
47 | 50 | void addBarset(); |
|
48 | 51 | void removeBarset(); |
|
49 | 52 | |
|
53 | void setLegendLeft(); | |
|
54 | void setLegendRight(); | |
|
55 | void setLegendTop(); | |
|
56 | void setLegendBottom(); | |
|
57 | ||
|
58 | void updateLegendLayout(); | |
|
59 | ||
|
50 | 60 | private: |
|
51 | 61 | |
|
52 | 62 | QChart *m_chart; |
@@ -56,8 +66,12 private: | |||
|
56 | 66 | QGridLayout *m_mainLayout; |
|
57 | 67 | QGridLayout *m_buttonLayout; |
|
58 | 68 | |
|
59 | QGraphicsView *m_customView; | |
|
60 | QGraphicsScene *m_customScene; | |
|
69 | // For detached layout | |
|
70 | QGroupBox* m_legendSettings; | |
|
71 | QDoubleSpinBox *m_legendPosX; | |
|
72 | QDoubleSpinBox *m_legendPosY; | |
|
73 | QDoubleSpinBox *m_legendWidth; | |
|
74 | QDoubleSpinBox *m_legendHeight; | |
|
61 | 75 | }; |
|
62 | 76 | |
|
63 | 77 | #endif // MAINWIDGET_H |
@@ -318,8 +318,6 void ChartPresenter::updateLayout() | |||
|
318 | 318 | // recalculate legend position |
|
319 | 319 | if (legend != 0 && legend->isAttachedToChart() && legend->isEnabled()) { |
|
320 | 320 | |
|
321 | QRect legendRect; | |
|
322 | ||
|
323 | 321 | // Reserve some space for legend |
|
324 | 322 | switch (legend->alignment()) { |
|
325 | 323 | |
@@ -382,7 +380,9 void ChartPresenter::updateLayout() | |||
|
382 | 380 | |
|
383 | 381 | QRectF chartRect = m_rect.adjusted(m_chartMargins.left(),m_chartMargins.top(),-m_chartMargins.right(),-m_chartMargins.bottom()); |
|
384 | 382 | |
|
385 | legend->setGeometry(m_rect.adjusted(m_legendMargins.left(),m_legendMargins.top(),-m_legendMargins.right(),-m_legendMargins.bottom())); | |
|
383 | if (legend != 0 && legend->isAttachedToChart() && legend->isEnabled()) { | |
|
384 | legend->setGeometry(m_rect.adjusted(m_legendMargins.left(),m_legendMargins.top(),-m_legendMargins.right(),-m_legendMargins.bottom())); | |
|
385 | } | |
|
386 | 386 | |
|
387 | 387 | if(m_chartRect!=chartRect && chartRect.isValid()){ |
|
388 | 388 | m_chartRect=chartRect; |
@@ -320,29 +320,38 QLegendPrivate::~QLegendPrivate() | |||
|
320 | 320 | |
|
321 | 321 | void QLegendPrivate::setOffset(qreal x, qreal y) |
|
322 | 322 | { |
|
323 | ||
|
323 | bool scrollHorizontal = true; | |
|
324 | 324 | switch(m_alignment) { |
|
325 | ||
|
326 | 325 | case Qt::AlignTop: |
|
327 | 326 | case Qt::AlignBottom: { |
|
328 | if(m_width<=m_rect.width()) return; | |
|
329 | ||
|
330 | if (x != m_offsetX) { | |
|
331 | m_offsetX = qBound(qreal(0), x, m_width - m_rect.width()); | |
|
332 | m_markers->setPos(-m_offsetX,m_rect.top()); | |
|
333 | } | |
|
327 | scrollHorizontal = true; | |
|
334 | 328 | break; |
|
335 | 329 | } |
|
336 | 330 | case Qt::AlignLeft: |
|
337 | 331 | case Qt::AlignRight: { |
|
332 | scrollHorizontal = false; | |
|
333 | break; | |
|
334 | } | |
|
335 | } | |
|
338 | 336 | |
|
339 | if(m_height<=m_rect.height()) return; | |
|
337 | // If detached, the scrolling and layout logic is inverted. | |
|
338 | if (!m_attachedToChart) { | |
|
339 | scrollHorizontal = !scrollHorizontal; | |
|
340 | } | |
|
340 | 341 | |
|
341 | if (y != m_offsetY) { | |
|
342 | m_offsetY = qBound(qreal(0), y, m_height - m_rect.height()); | |
|
343 | m_markers->setPos(m_rect.left(),-m_offsetY); | |
|
344 | } | |
|
345 | break; | |
|
342 | if (scrollHorizontal) { | |
|
343 | if(m_width<=m_rect.width()) return; | |
|
344 | ||
|
345 | if (x != m_offsetX) { | |
|
346 | m_offsetX = qBound(qreal(0), x, m_width - m_rect.width()); | |
|
347 | m_markers->setPos(-m_offsetX,m_rect.top()); | |
|
348 | } | |
|
349 | } else { | |
|
350 | if(m_height<=m_rect.height()) return; | |
|
351 | ||
|
352 | if (y != m_offsetY) { | |
|
353 | m_offsetY = qBound(qreal(0), y, m_height - m_rect.height()); | |
|
354 | m_markers->setPos(m_rect.left(),-m_offsetY); | |
|
346 | 355 | } |
|
347 | 356 | } |
|
348 | 357 | } |
@@ -350,6 +359,11 void QLegendPrivate::setOffset(qreal x, qreal y) | |||
|
350 | 359 | |
|
351 | 360 | void QLegendPrivate::updateLayout() |
|
352 | 361 | { |
|
362 | if (!m_attachedToChart) { | |
|
363 | updateDetachedLayout(); | |
|
364 | return; | |
|
365 | } | |
|
366 | ||
|
353 | 367 | m_offsetX=0; |
|
354 | 368 | QList<QGraphicsItem *> items = m_markers->childItems(); |
|
355 | 369 | |
@@ -406,8 +420,136 void QLegendPrivate::updateLayout() | |||
|
406 | 420 | break; |
|
407 | 421 | } |
|
408 | 422 | |
|
409 | if (m_attachedToChart) { | |
|
410 | m_presenter->updateLayout(); | |
|
423 | m_presenter->updateLayout(); | |
|
424 | } | |
|
425 | ||
|
426 | void QLegendPrivate::updateDetachedLayout() | |
|
427 | { | |
|
428 | m_offsetX=0; | |
|
429 | QList<QGraphicsItem *> items = m_markers->childItems(); | |
|
430 | ||
|
431 | if(items.isEmpty()) return; | |
|
432 | ||
|
433 | m_minWidth = 0; | |
|
434 | m_minHeight = 0; | |
|
435 | ||
|
436 | switch (m_alignment) { | |
|
437 | case Qt::AlignTop: { | |
|
438 | QPointF point = m_rect.topLeft(); | |
|
439 | m_width = 0; | |
|
440 | m_height = 0; | |
|
441 | for (int i=0; i<items.count(); i++) { | |
|
442 | QGraphicsItem *item = items.at(i); | |
|
443 | const QRectF& rect = item->boundingRect(); | |
|
444 | qreal w = rect.width(); | |
|
445 | qreal h = rect.height(); | |
|
446 | m_minWidth = qMax(m_minWidth,w); | |
|
447 | m_minHeight = qMax(m_minHeight,rect.height()); | |
|
448 | m_height = qMax(m_height,h); | |
|
449 | item->setPos(point.x(),point.y()); | |
|
450 | point.setX(point.x() + w); | |
|
451 | if (point.x() + w > m_rect.topLeft().x() + m_rect.width()) { | |
|
452 | // Next item would go off rect. | |
|
453 | point.setX(m_rect.topLeft().x()); | |
|
454 | point.setY(point.y() + h); | |
|
455 | if (i+1 < items.count()) { | |
|
456 | m_height += h; | |
|
457 | } | |
|
458 | } | |
|
459 | } | |
|
460 | m_markers->setPos(m_rect.topLeft()); | |
|
461 | m_width = m_minWidth; | |
|
462 | } | |
|
463 | break; | |
|
464 | case Qt::AlignBottom: { | |
|
465 | QPointF point = m_rect.bottomLeft(); | |
|
466 | m_width = 0; | |
|
467 | m_height = 0; | |
|
468 | for (int i=0; i<items.count(); i++) { | |
|
469 | QGraphicsItem *item = items.at(i); | |
|
470 | const QRectF& rect = item->boundingRect(); | |
|
471 | qreal w = rect.width(); | |
|
472 | qreal h = rect.height(); | |
|
473 | m_minWidth = qMax(m_minWidth,w); | |
|
474 | m_minHeight = qMax(m_minHeight,rect.height()); | |
|
475 | m_height = qMax(m_height,h); | |
|
476 | item->setPos(point.x(),point.y() - h); | |
|
477 | point.setX(point.x() + w); | |
|
478 | if (point.x() + w > m_rect.bottomLeft().x() + m_rect.width()) { | |
|
479 | // Next item would go off rect. | |
|
480 | point.setX(m_rect.bottomLeft().x()); | |
|
481 | point.setY(point.y() - h); | |
|
482 | if (i+1 < items.count()) { | |
|
483 | m_height += h; | |
|
484 | } | |
|
485 | } | |
|
486 | } | |
|
487 | m_markers->setPos(m_rect.topLeft()); | |
|
488 | m_width = m_minWidth; | |
|
489 | } | |
|
490 | break; | |
|
491 | case Qt::AlignLeft: { | |
|
492 | QPointF point = m_rect.topLeft(); | |
|
493 | m_width = 0; | |
|
494 | m_height = 0; | |
|
495 | qreal maxWidth = 0; | |
|
496 | for (int i=0; i<items.count(); i++) { | |
|
497 | QGraphicsItem *item = items.at(i); | |
|
498 | const QRectF& rect = item->boundingRect(); | |
|
499 | qreal w = rect.width(); | |
|
500 | qreal h = rect.height(); | |
|
501 | m_minWidth = qMax(m_minWidth,rect.width()); | |
|
502 | m_minHeight = qMax(m_minHeight,h); | |
|
503 | maxWidth = qMax(maxWidth,w); | |
|
504 | m_width = qMax(m_width, maxWidth); | |
|
505 | item->setPos(point.x(),point.y()); | |
|
506 | point.setY(point.y() + h); | |
|
507 | if (point.y() + h > m_rect.topLeft().y() + m_rect.height()) { | |
|
508 | // Next item would go off rect. | |
|
509 | point.setX(point.x() + maxWidth); | |
|
510 | point.setY(m_rect.topLeft().y()); | |
|
511 | if (i+1 < items.count()) { | |
|
512 | m_width += maxWidth; | |
|
513 | maxWidth = 0; | |
|
514 | } | |
|
515 | } | |
|
516 | } | |
|
517 | m_markers->setPos(m_rect.topLeft()); | |
|
518 | m_height = m_minHeight; | |
|
519 | } | |
|
520 | break; | |
|
521 | case Qt::AlignRight: { | |
|
522 | QPointF point = m_rect.topRight(); | |
|
523 | m_width = 0; | |
|
524 | m_height = 0; | |
|
525 | qreal maxWidth = 0; | |
|
526 | for (int i=0; i<items.count(); i++) { | |
|
527 | QGraphicsItem *item = items.at(i); | |
|
528 | const QRectF& rect = item->boundingRect(); | |
|
529 | qreal w = rect.width(); | |
|
530 | qreal h = rect.height(); | |
|
531 | m_minWidth = qMax(m_minWidth,rect.width()); | |
|
532 | m_minHeight = qMax(m_minHeight,h); | |
|
533 | maxWidth = qMax(maxWidth,w); | |
|
534 | m_width = qMax(m_width, maxWidth); | |
|
535 | item->setPos(point.x() - w,point.y()); | |
|
536 | point.setY(point.y() + h); | |
|
537 | if (point.y() + h > m_rect.topLeft().y() + m_rect.height()) { | |
|
538 | // Next item would go off rect. | |
|
539 | point.setX(point.x() - maxWidth); | |
|
540 | point.setY(m_rect.topLeft().y()); | |
|
541 | if (i+1 < items.count()) { | |
|
542 | m_width += maxWidth; | |
|
543 | maxWidth = 0; | |
|
544 | } | |
|
545 | } | |
|
546 | } | |
|
547 | m_markers->setPos(m_rect.topLeft()); | |
|
548 | m_height = m_minHeight; | |
|
549 | } | |
|
550 | break; | |
|
551 | default: | |
|
552 | break; | |
|
411 | 553 | } |
|
412 | 554 | } |
|
413 | 555 |
General Comments 0
You need to be logged in to leave comments.
Login now