Elastic Nodes Example▲
Sélectionnez
/**
**************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
***************************************************************************
*/
#include
"graphwidget.h"
#include
"edge.h"
#include
"node.h"
#include <math.h>
#include <QKeyEvent>
#include <QRandomGenerator>
GraphWidget::
GraphWidget(QWidget *
parent)
:
QGraphicsView(parent), timerId(0
)
{
QGraphicsScene *
scene =
new
QGraphicsScene(this
);
scene-&
gt;setItemIndexMethod(QGraphicsScene::
NoIndex);
scene-&
gt;setSceneRect(-
200
, -
200
, 400
, 400
);
setScene(scene);
setCacheMode(CacheBackground);
setViewportUpdateMode(BoundingRectViewportUpdate);
setRenderHint(QPainter::
Antialiasing);
setTransformationAnchor(AnchorUnderMouse);
scale(qreal(0.8
), qreal(0.8
));
setMinimumSize(400
, 400
);
setWindowTitle(tr("Elastic Nodes"
));
Node *
node1 =
new
Node(this
);
Node *
node2 =
new
Node(this
);
Node *
node3 =
new
Node(this
);
Node *
node4 =
new
Node(this
);
centerNode =
new
Node(this
);
Node *
node6 =
new
Node(this
);
Node *
node7 =
new
Node(this
);
Node *
node8 =
new
Node(this
);
Node *
node9 =
new
Node(this
);
scene-&
gt;addItem(node1);
scene-&
gt;addItem(node2);
scene-&
gt;addItem(node3);
scene-&
gt;addItem(node4);
scene-&
gt;addItem(centerNode);
scene-&
gt;addItem(node6);
scene-&
gt;addItem(node7);
scene-&
gt;addItem(node8);
scene-&
gt;addItem(node9);
scene-&
gt;addItem(new
Edge(node1, node2));
scene-&
gt;addItem(new
Edge(node2, node3));
scene-&
gt;addItem(new
Edge(node2, centerNode));
scene-&
gt;addItem(new
Edge(node3, node6));
scene-&
gt;addItem(new
Edge(node4, node1));
scene-&
gt;addItem(new
Edge(node4, centerNode));
scene-&
gt;addItem(new
Edge(centerNode, node6));
scene-&
gt;addItem(new
Edge(centerNode, node8));
scene-&
gt;addItem(new
Edge(node6, node9));
scene-&
gt;addItem(new
Edge(node7, node4));
scene-&
gt;addItem(new
Edge(node8, node7));
scene-&
gt;addItem(new
Edge(node9, node8));
node1-&
gt;setPos(-
50
, -
50
);
node2-&
gt;setPos(0
, -
50
);
node3-&
gt;setPos(50
, -
50
);
node4-&
gt;setPos(-
50
, 0
);
centerNode-&
gt;setPos(0
, 0
);
node6-&
gt;setPos(50
, 0
);
node7-&
gt;setPos(-
50
, 50
);
node8-&
gt;setPos(0
, 50
);
node9-&
gt;setPos(50
, 50
);
}
void
GraphWidget::
itemMoved()
{
if
(!
timerId)
timerId =
startTimer(1000
/
25
);
}
void
GraphWidget::
keyPressEvent(QKeyEvent *
event)
{
switch
(event-&
gt;key()) {
case
Qt::
Key_Up:
centerNode-&
gt;moveBy(0
, -
20
);
break
;
case
Qt::
Key_Down:
centerNode-&
gt;moveBy(0
, 20
);
break
;
case
Qt::
Key_Left:
centerNode-&
gt;moveBy(-
20
, 0
);
break
;
case
Qt::
Key_Right:
centerNode-&
gt;moveBy(20
, 0
);
break
;
case
Qt::
Key_Plus:
zoomIn();
break
;
case
Qt::
Key_Minus:
zoomOut();
break
;
case
Qt::
Key_Space:
case
Qt::
Key_Enter:
shuffle();
break
;
default
:
QGraphicsView::
keyPressEvent(event);
}
}
void
GraphWidget::
timerEvent(QTimerEvent *
event)
{
Q_UNUSED(event);
QList&
lt;Node *&
gt; nodes;
foreach (QGraphicsItem *
item, scene()-&
gt;items()) {
if
(Node *
node =
qgraphicsitem_cast&
lt;Node *&
gt;(item))
nodes &
lt;&
lt; node;
}
foreach (Node *
node, nodes)
node-&
gt;calculateForces();
bool
itemsMoved =
false
;
foreach (Node *
node, nodes) {
if
(node-&
gt;advancePosition())
itemsMoved =
true
;
}
if
(!
itemsMoved) {
killTimer(timerId);
timerId =
0
;
}
}
#if QT_CONFIG(wheelevent)
void
GraphWidget::
wheelEvent(QWheelEvent *
event)
{
scaleView(pow((double
)2
, -
event-&
gt;delta() /
240.0
));
}
#endif
void
GraphWidget::
drawBackground(QPainter *
painter, const
QRectF &
amp;rect)
{
Q_UNUSED(rect);
// Shadow
QRectF sceneRect =
this
-&
gt;sceneRect();
QRectF rightShadow(sceneRect.right(), sceneRect.top() +
5
, 5
, sceneRect.height());
QRectF bottomShadow(sceneRect.left() +
5
, sceneRect.bottom(), sceneRect.width(), 5
);
if
(rightShadow.intersects(rect) ||
rightShadow.contains(rect))
painter-&
gt;fillRect(rightShadow, Qt::
darkGray);
if
(bottomShadow.intersects(rect) ||
bottomShadow.contains(rect))
painter-&
gt;fillRect(bottomShadow, Qt::
darkGray);
// Fill
QLinearGradient gradient(sceneRect.topLeft(), sceneRect.bottomRight());
gradient.setColorAt(0
, Qt::
white);
gradient.setColorAt(1
, Qt::
lightGray);
painter-&
gt;fillRect(rect.intersected(sceneRect), gradient);
painter-&
gt;setBrush(Qt::
NoBrush);
painter-&
gt;drawRect(sceneRect);
// Text
QRectF textRect(sceneRect.left() +
4
, sceneRect.top() +
4
,
sceneRect.width() -
4
, sceneRect.height() -
4
);
QString message(tr("Click and drag the nodes around, and zoom with the mouse "
"wheel or the '+' and '-' keys"
));
QFont font =
painter-&
gt;font();
font.setBold(true
);
font.setPointSize(14
);
painter-&
gt;setFont(font);
painter-&
gt;setPen(Qt::
lightGray);
painter-&
gt;drawText(textRect.translated(2
, 2
), message);
painter-&
gt;setPen(Qt::
black);
painter-&
gt;drawText(textRect, message);
}
void
GraphWidget::
scaleView(qreal scaleFactor)
{
qreal factor =
transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0
, 0
, 1
, 1
)).width();
if
(factor &
lt; 0.07
||
factor &
gt; 100
)
return
;
scale(scaleFactor, scaleFactor);
}
void
GraphWidget::
shuffle()
{
foreach (QGraphicsItem *
item, scene()-&
gt;items()) {
if
(qgraphicsitem_cast&
lt;Node *&
gt;(item))
item-&
gt;setPos(-
150
+
QRandomGenerator::
global()-&
gt;bounded(300
), -
150
+
QRandomGenerator::
global()-&
gt;bounded(300
));
}
}
void
GraphWidget::
zoomIn()
{
scaleView(qreal(1.2
));
}
void
GraphWidget::
zoomOut()
{
scaleView(1
/
qreal(1.2
));
}