@@ -0,0 +1,102 | |||||
|
1 | #include "callout.h" | |||
|
2 | #include <QPainter> | |||
|
3 | #include <QFontMetrics> | |||
|
4 | #include <QGraphicsSceneMouseEvent> | |||
|
5 | #include <QCursor> | |||
|
6 | ||||
|
7 | Callout::Callout(QGraphicsItem * parent): | |||
|
8 | QGraphicsItem(parent) | |||
|
9 | { | |||
|
10 | } | |||
|
11 | ||||
|
12 | QRectF Callout::boundingRect() const | |||
|
13 | { | |||
|
14 | QPointF anchor = mapFromParent(m_anchor); | |||
|
15 | QRectF rect; | |||
|
16 | rect.setLeft(qMin(m_textRect.left(), anchor.x())); | |||
|
17 | rect.setRight(qMax(m_textRect.right(), anchor.x())); | |||
|
18 | rect.setTop(qMin(m_textRect.top(), anchor.y())); | |||
|
19 | rect.setBottom(qMax(m_textRect.bottom(), anchor.y())); | |||
|
20 | return rect; | |||
|
21 | } | |||
|
22 | ||||
|
23 | void Callout::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) | |||
|
24 | { | |||
|
25 | Q_UNUSED(option) | |||
|
26 | Q_UNUSED(widget) | |||
|
27 | QPainterPath path; | |||
|
28 | path.addRoundedRect(m_textRect, 5, 5); | |||
|
29 | ||||
|
30 | QPointF anchor = mapFromParent(m_anchor); | |||
|
31 | if (!m_textRect.contains(anchor)) { | |||
|
32 | QPointF point1, point2; | |||
|
33 | ||||
|
34 | // establish the position of the anchor point in relation to m_textRect | |||
|
35 | bool above = anchor.y() <= m_textRect.top(); | |||
|
36 | bool aboveCenter = anchor.y() > m_textRect.top() && anchor.y() <= m_textRect.center().y(); | |||
|
37 | bool belowCenter = anchor.y() > m_textRect.center().y() && anchor.y() <= m_textRect.bottom(); | |||
|
38 | bool below = anchor.y() > m_textRect.bottom(); | |||
|
39 | ||||
|
40 | bool onLeft = anchor.x() <= m_textRect.left(); | |||
|
41 | bool leftOfCenter = anchor.x() > m_textRect.left() && anchor.x() <= m_textRect.center().x(); | |||
|
42 | bool rightOfCenter = anchor.x() > m_textRect.center().x() && anchor.x() <= m_textRect.right(); | |||
|
43 | bool onRight = anchor.x() > m_textRect.right(); | |||
|
44 | ||||
|
45 | // get the nearest m_textRect corner. | |||
|
46 | qreal x = (onRight + rightOfCenter) * m_textRect.width(); | |||
|
47 | qreal y = (below + belowCenter) * m_textRect.height(); | |||
|
48 | bool cornerCase = (above && onLeft) || (above && onRight) || (below && onLeft) || (below && onRight); | |||
|
49 | bool vertical = qAbs(anchor.x() - x) > qAbs(anchor.y() - y); | |||
|
50 | ||||
|
51 | qreal x1 = x + leftOfCenter * 10 - rightOfCenter * 20 + cornerCase * !vertical * (onLeft * 10 - onRight * 20); | |||
|
52 | qreal y1 = y + aboveCenter * 10 - belowCenter * 20 + cornerCase * vertical * (above * 10 - below * 20);; | |||
|
53 | point1.setX(x1); | |||
|
54 | point1.setY(y1); | |||
|
55 | ||||
|
56 | qreal x2 = x + leftOfCenter * 20 - rightOfCenter * 10 + cornerCase * !vertical * (onLeft * 20 - onRight * 10);; | |||
|
57 | qreal y2 = y + aboveCenter * 20 - belowCenter * 10 + cornerCase * vertical * (above * 20 - below * 10);; | |||
|
58 | point2.setX(x2); | |||
|
59 | point2.setY(y2); | |||
|
60 | ||||
|
61 | path.moveTo(point1); | |||
|
62 | path.lineTo(mapFromParent(m_anchor)); | |||
|
63 | path.lineTo(point2); | |||
|
64 | path = path.simplified(); | |||
|
65 | } | |||
|
66 | painter->setBrush(QColor(255, 255, 255)); | |||
|
67 | painter->drawPath(path); | |||
|
68 | painter->drawText(m_textRect.adjusted(2, 2, 0, 0), m_text); | |||
|
69 | } | |||
|
70 | ||||
|
71 | void Callout::mousePressEvent(QGraphicsSceneMouseEvent *event) | |||
|
72 | { | |||
|
73 | if (m_textRect.contains(event->pos())) { | |||
|
74 | m_clickOffset = event->pos(); | |||
|
75 | event->setAccepted(true); | |||
|
76 | } else { | |||
|
77 | event->setAccepted(false); | |||
|
78 | } | |||
|
79 | } | |||
|
80 | ||||
|
81 | void Callout::mouseMoveEvent(QGraphicsSceneMouseEvent *event) | |||
|
82 | { | |||
|
83 | if (m_textRect.contains(event->pos())){ | |||
|
84 | setPos(mapToParent(event->pos() - m_clickOffset)); | |||
|
85 | event->setAccepted(true); | |||
|
86 | } else { | |||
|
87 | event->setAccepted(false); | |||
|
88 | } | |||
|
89 | } | |||
|
90 | ||||
|
91 | void Callout::setText(const QString &text) | |||
|
92 | { | |||
|
93 | m_text = text; | |||
|
94 | QFontMetrics metrics(m_font); | |||
|
95 | prepareGeometryChange(); | |||
|
96 | m_textRect = metrics.boundingRect(QRect(0, 0, 150, 150), Qt::AlignLeft, m_text).adjusted(0, 0, 4, 4); | |||
|
97 | } | |||
|
98 | ||||
|
99 | void Callout::setAnchor(QPointF point) | |||
|
100 | { | |||
|
101 | m_anchor = point; | |||
|
102 | } |
@@ -0,0 +1,32 | |||||
|
1 | #ifndef CALLOUT_H | |||
|
2 | #define CALLOUT_H | |||
|
3 | ||||
|
4 | #include <QGraphicsItem> | |||
|
5 | #include <QFont> | |||
|
6 | ||||
|
7 | class QGraphicsSceneMouseEvent; | |||
|
8 | ||||
|
9 | class Callout : public QGraphicsItem | |||
|
10 | { | |||
|
11 | public: | |||
|
12 | Callout(QGraphicsItem * parent = 0); | |||
|
13 | ||||
|
14 | void setText(const QString &text); | |||
|
15 | void setAnchor(QPointF point); | |||
|
16 | ||||
|
17 | QRectF boundingRect() const; | |||
|
18 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget); | |||
|
19 | ||||
|
20 | protected: | |||
|
21 | void mousePressEvent(QGraphicsSceneMouseEvent *event); | |||
|
22 | void mouseMoveEvent(QGraphicsSceneMouseEvent *event); | |||
|
23 | ||||
|
24 | private: | |||
|
25 | QString m_text; | |||
|
26 | QRectF m_textRect; | |||
|
27 | QPointF m_anchor; | |||
|
28 | QFont m_font; | |||
|
29 | QPointF m_clickOffset; | |||
|
30 | }; | |||
|
31 | ||||
|
32 | #endif // CALLOUT_H |
@@ -0,0 +1,13 | |||||
|
1 | !include( ../examples.pri ) { | |||
|
2 | error( "Couldn't find the examples.pri file!" ) | |||
|
3 | } | |||
|
4 | ||||
|
5 | TARGET = callout | |||
|
6 | TEMPLATE = app | |||
|
7 | ||||
|
8 | SOURCES += main.cpp\ | |||
|
9 | widget.cpp \ | |||
|
10 | callout.cpp | |||
|
11 | ||||
|
12 | HEADERS += widget.h \ | |||
|
13 | callout.h |
@@ -0,0 +1,11 | |||||
|
1 | #include <QApplication> | |||
|
2 | #include "widget.h" | |||
|
3 | ||||
|
4 | int main(int argc, char *argv[]) | |||
|
5 | { | |||
|
6 | QApplication a(argc, argv); | |||
|
7 | Widget w; | |||
|
8 | w.show(); | |||
|
9 | ||||
|
10 | return a.exec(); | |||
|
11 | } |
@@ -0,0 +1,56 | |||||
|
1 | #include "widget.h" | |||
|
2 | #include <QGraphicsScene> | |||
|
3 | #include <QGraphicsView> | |||
|
4 | #include <QVBoxLayout> | |||
|
5 | #include <QChart> | |||
|
6 | #include <QLineSeries> | |||
|
7 | #include <QGraphicsTextItem> | |||
|
8 | #include <QGraphicsLineItem> | |||
|
9 | #include "callout.h" | |||
|
10 | ||||
|
11 | QTCOMMERCIALCHART_USE_NAMESPACE | |||
|
12 | ||||
|
13 | Widget::Widget(QWidget *parent) | |||
|
14 | : QWidget(parent), | |||
|
15 | m_scene(0), | |||
|
16 | m_chart(0), | |||
|
17 | m_view(0) | |||
|
18 | { | |||
|
19 | // chart | |||
|
20 | m_chart = new QChart; | |||
|
21 | m_chart->setMinimumSize(640, 480); | |||
|
22 | QLineSeries *series = new QLineSeries; | |||
|
23 | series->setName("Click the line to create a movable callout"); | |||
|
24 | series->append(1, 3); | |||
|
25 | series->append(4, 5); | |||
|
26 | series->append(5, 4.5); | |||
|
27 | series->append(7, 1); | |||
|
28 | series->append(11, 2); | |||
|
29 | m_chart->addSeries(series); | |||
|
30 | m_chart->createDefaultAxes(); | |||
|
31 | ||||
|
32 | m_scene = new QGraphicsScene; | |||
|
33 | m_view = new QGraphicsView(m_scene); | |||
|
34 | m_view->setRenderHint(QPainter::Antialiasing); | |||
|
35 | m_scene->addItem(m_chart); | |||
|
36 | ||||
|
37 | QVBoxLayout *mainLayout = new QVBoxLayout; | |||
|
38 | mainLayout->addWidget(m_view); | |||
|
39 | setLayout(mainLayout); | |||
|
40 | ||||
|
41 | connect(series, SIGNAL(clicked(QPointF)), this, SLOT(addCallout(QPointF))); | |||
|
42 | } | |||
|
43 | ||||
|
44 | Widget::~Widget() | |||
|
45 | { | |||
|
46 | ||||
|
47 | } | |||
|
48 | ||||
|
49 | void Widget::addCallout(QPointF point) | |||
|
50 | { | |||
|
51 | Callout *label = new Callout(m_chart); | |||
|
52 | label->setText(QString("X: %1\nY: %2").arg(point.x()).arg(point.y())); | |||
|
53 | label->setAnchor(m_chart->mapFromParent(m_view->mapToScene(m_view->mapFromGlobal(QCursor::pos())))); | |||
|
54 | label->setPos(m_chart->mapFromParent(m_view->mapToScene(m_view->mapFromGlobal(QCursor::pos() + QPoint(10, -50))))); | |||
|
55 | label->setZValue(11); | |||
|
56 | } |
@@ -0,0 +1,29 | |||||
|
1 | #ifndef WIDGET_H | |||
|
2 | #define WIDGET_H | |||
|
3 | ||||
|
4 | #include <QWidget> | |||
|
5 | #include <QChart> | |||
|
6 | ||||
|
7 | class QGraphicsScene; | |||
|
8 | class QGraphicsView; | |||
|
9 | ||||
|
10 | QTCOMMERCIALCHART_USE_NAMESPACE | |||
|
11 | ||||
|
12 | class Widget : public QWidget | |||
|
13 | { | |||
|
14 | Q_OBJECT | |||
|
15 | ||||
|
16 | public: | |||
|
17 | Widget(QWidget *parent = 0); | |||
|
18 | ~Widget(); | |||
|
19 | ||||
|
20 | public slots: | |||
|
21 | void addCallout(QPointF point); | |||
|
22 | ||||
|
23 | private: | |||
|
24 | QGraphicsScene *m_scene; | |||
|
25 | QChart *m_chart; | |||
|
26 | QGraphicsView *m_view; | |||
|
27 | }; | |||
|
28 | ||||
|
29 | #endif // WIDGET_H |
General Comments 0
You need to be logged in to leave comments.
Login now